mirror of
git://sourceware.org/git/lvm2.git
synced 2025-10-23 23:33:15 +03:00
Compare commits
2 Commits
dev-bmr-dm
...
dev-bmr-dm
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d4acf8b533 | ||
|
|
dfb4560e24 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -7,8 +7,6 @@
|
|||||||
*.orig
|
*.orig
|
||||||
*.pc
|
*.pc
|
||||||
*.pot
|
*.pot
|
||||||
*.pyc
|
|
||||||
*.pyo
|
|
||||||
*.rej
|
*.rej
|
||||||
*.so
|
*.so
|
||||||
*.so.*
|
*.so.*
|
||||||
|
|||||||
4
COPYING
4
COPYING
@@ -2,7 +2,7 @@
|
|||||||
Version 2, June 1991
|
Version 2, June 1991
|
||||||
|
|
||||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
of this license document, but changing it is not allowed.
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
@@ -305,7 +305,7 @@ the "copyright" line and a pointer to where the full notice is found.
|
|||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|||||||
24
Makefile.in
24
Makefile.in
@@ -10,7 +10,7 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program; if not, write to the Free Software Foundation,
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
srcdir = @srcdir@
|
srcdir = @srcdir@
|
||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
@@ -95,7 +95,7 @@ endif
|
|||||||
DISTCLEAN_TARGETS += cscope.out
|
DISTCLEAN_TARGETS += cscope.out
|
||||||
CLEAN_DIRS += autom4te.cache
|
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 $(@)
|
$(MAKE) -C test $(@)
|
||||||
|
|
||||||
conf.generate: tools
|
conf.generate: tools
|
||||||
@@ -131,9 +131,6 @@ rpm: dist
|
|||||||
generate: conf.generate
|
generate: conf.generate
|
||||||
$(MAKE) -C conf generate
|
$(MAKE) -C conf generate
|
||||||
|
|
||||||
all_man:
|
|
||||||
$(MAKE) -C man all_man
|
|
||||||
|
|
||||||
install_system_dirs:
|
install_system_dirs:
|
||||||
$(INSTALL_DIR) $(DESTDIR)$(DEFAULT_SYS_DIR)
|
$(INSTALL_DIR) $(DESTDIR)$(DEFAULT_SYS_DIR)
|
||||||
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_ARCHIVE_DIR)
|
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_ARCHIVE_DIR)
|
||||||
@@ -153,9 +150,6 @@ install_systemd_generators:
|
|||||||
install_systemd_units:
|
install_systemd_units:
|
||||||
$(MAKE) -C scripts install_systemd_units
|
$(MAKE) -C scripts install_systemd_units
|
||||||
|
|
||||||
install_all_man:
|
|
||||||
$(MAKE) -C man install_all_man
|
|
||||||
|
|
||||||
ifeq ("@PYTHON_BINDINGS@", "yes")
|
ifeq ("@PYTHON_BINDINGS@", "yes")
|
||||||
install_python_bindings:
|
install_python_bindings:
|
||||||
$(MAKE) -C liblvm/python install_python_bindings
|
$(MAKE) -C liblvm/python install_python_bindings
|
||||||
@@ -166,11 +160,8 @@ install_tmpfiles_configuration:
|
|||||||
|
|
||||||
LCOV_TRACES = libdm.info lib.info liblvm.info tools.info \
|
LCOV_TRACES = libdm.info lib.info liblvm.info tools.info \
|
||||||
libdaemon/client.info libdaemon/server.info \
|
libdaemon/client.info libdaemon/server.info \
|
||||||
daemons/clvmd.info \
|
daemons/clvmd.info daemons/dmeventd.info \
|
||||||
daemons/dmeventd.info \
|
daemons/lvmetad.info
|
||||||
daemons/lvmetad.info \
|
|
||||||
daemons/lvmlockd.info \
|
|
||||||
daemons/lvmpolld.info
|
|
||||||
|
|
||||||
CLEAN_TARGETS += $(LCOV_TRACES)
|
CLEAN_TARGETS += $(LCOV_TRACES)
|
||||||
|
|
||||||
@@ -235,9 +226,10 @@ endif
|
|||||||
|
|
||||||
ifneq ($(shell which ctags),)
|
ifneq ($(shell which ctags),)
|
||||||
.PHONY: tags
|
.PHONY: tags
|
||||||
|
all: tags
|
||||||
tags:
|
tags:
|
||||||
test -z "$(shell find $(top_srcdir) -type f -name '*.[ch]' -newer tags 2>/dev/null | head -1)" || $(RM) tags
|
test -z "$(shell find $(top_srcdir) -type f -name '*.[ch]' -newer tags | head -1)" || $(RM) tags
|
||||||
test -f tags || find $(top_srcdir) -maxdepth 5 -type f -name '*.[ch]' -exec ctags -a '{}' +
|
test -f tags || find $(top_srcdir) -maxdepth 4 -type f -name '*.[ch]' -exec ctags -a '{}' +
|
||||||
|
|
||||||
CLEAN_TARGETS += tags
|
DISTCLEAN_TARGETS += tags
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1.02.129-git (2016-06-25)
|
1.02.104-git (2015-07-24)
|
||||||
|
|||||||
417
WHATS_NEW
417
WHATS_NEW
@@ -1,421 +1,8 @@
|
|||||||
Version 2.02.159 -
|
Version 2.02.127 -
|
||||||
=================================
|
=================================
|
||||||
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.
|
|
||||||
If PV belongs to some VG and metadata missing, skip it if system ID is used.
|
|
||||||
Automatically change PV header extension to latest version if writing PV/VG.
|
|
||||||
Identify used PVs in pv_attr field by new 'u' character.
|
|
||||||
Add pv_in_use reporting field to report if PV is used or not.
|
|
||||||
Add pv_ext_vsn reporting field to report PV header extension version.
|
|
||||||
Add protective flag marking PVs as used even if no metadata available.
|
|
||||||
|
|
||||||
Version 2.02.142 - 15th February 2016
|
|
||||||
=====================================
|
|
||||||
Fix memory pool corruption in pvmove (2.02.141).
|
|
||||||
Support control of spare metadata creation when repairing thin-pool.
|
|
||||||
Fix config type of 'log/verbose' from bool to int (2.02.99).
|
|
||||||
Fix inverted data LV thinp watermark calc for dmeventd response (2.02.133).
|
|
||||||
Use use_blkid_wiping=0 if not defined in lvm.conf and support not compiled in.
|
|
||||||
Do not check for suspended devices if scanning for lvmetad update.
|
|
||||||
Clear cached bootloader areas when PV format changed.
|
|
||||||
Fix partn table filter with external_device_info_source="udev" and blkid<2.20.
|
|
||||||
|
|
||||||
Version 2.02.141 - 25th January 2016
|
|
||||||
====================================
|
|
||||||
Add metadata/check_pv_device_sizes switch to lvm.conf for device size checks.
|
|
||||||
Warn if device size is less than corresponding PV size in metadata.
|
|
||||||
Cache device sizes internally.
|
|
||||||
Restore support for command breaking in process_each_lv_in_vg() (2.02.118).
|
|
||||||
Use correct mempool when process_each_lv_in_vg() (2.02.118).
|
|
||||||
Fix lvm.8 man to show again prohibited suffixes.
|
|
||||||
Fix configure to set proper use_blkid_wiping if autodetected as disabled.
|
|
||||||
Initialise udev in clvmd for use in device scanning. (2.02.116)
|
|
||||||
Add seg_le_ranges report field for common format when displaying seg devices.
|
|
||||||
Honour report/list_item_separator for seg_metadata_le_ranges report field.
|
|
||||||
Don't mark hidden devs in -o devices,metadata_devices,seg_pe_ranges.(2.02.140)
|
|
||||||
Change LV sizes in seg_pe_ranges report field to match underlying devices.
|
|
||||||
Add kernel_cache_settings report field for cache LV settings used in kernel.
|
|
||||||
|
|
||||||
Version 2.02.140 - 16th January 2016
|
|
||||||
====================================
|
|
||||||
Fix lvm2app to return either 0 or 1 for lvm_vg_is_{clustered,exported}.
|
|
||||||
Add kernel_discards report field to display thin pool discard used in kernel.
|
|
||||||
Correct checking of target presence when driver access is disabled.
|
|
||||||
Eval poolmetadatasize arg earlier in lvresize.
|
|
||||||
Fix vgcfgrestore to respect allocatable attribute of PVs.
|
|
||||||
Add report/mark_hidden_devices to lvm.conf.
|
|
||||||
Use brackets consistently in report fields to mark hidden devices.
|
|
||||||
Restore background polling processing during auto-activation (2.02.119).
|
|
||||||
Fix invalid memory read when reporting cache LV policy_name (2.02.126).
|
|
||||||
|
|
||||||
Version 2.02.139 - 8th January 2016
|
|
||||||
===================================
|
|
||||||
Update lvmlockd with the new VG seqno before devices are suspended.
|
|
||||||
Rework vgrename to use the common processing code in toollib.
|
|
||||||
Make pvs show new devices on the system since the last .cache update.
|
|
||||||
Document F,D and M thin pool health status chars for lv_attr in lvs man page.
|
|
||||||
Also add lvm2-activation{-early,-net}.service systemd status for lvmdump -s.
|
|
||||||
|
|
||||||
Version 2.02.138 - 14th December 2015
|
|
||||||
=====================================
|
|
||||||
Support lvrename for hidden (used) cache pools.
|
|
||||||
Fix lvrename for stacked cache pools.
|
|
||||||
|
|
||||||
Version 2.02.137 - 5th December 2015
|
|
||||||
====================================
|
|
||||||
Restore archiving before changing metadata in vgextend (2.02.117).
|
|
||||||
Dropped internal usage of log_suppress(2).
|
|
||||||
Cleaned logging code for buffer size usage.
|
|
||||||
Added internal id_read_format_try() function to check and read valid UUID.
|
|
||||||
Change lvcreate, lvrename, lvresize to use process_each_vg.
|
|
||||||
Change process_each_vg to handle single VG as separate arg.
|
|
||||||
Issue error if ambiguous VG name is supplied in most commands.
|
|
||||||
Make process_each fns always work through full list of known VG names.
|
|
||||||
Use dm_get_status_mirror() instead of individual parsers.
|
|
||||||
Add mem pool arg for check_transient_status() target function.
|
|
||||||
Avoid misleading error with -m is omitted with lvconvert to raid types.
|
|
||||||
Add system_id to vginfo cache.
|
|
||||||
|
|
||||||
Version 2.02.136 - 28th November 2015
|
|
||||||
=====================================
|
|
||||||
Add new --sinceversion option for lvmconfig --type new.
|
|
||||||
Fix inactive table loaded for wrapping thin-pool when resizing it.
|
|
||||||
Extend the list of ignored libraries when locking memory.
|
|
||||||
|
|
||||||
Version 2.02.135 - 23rd November 2015
|
|
||||||
=====================================
|
|
||||||
Add a model file for Coverity.
|
|
||||||
Show correct error message for unsupported yet cache pool repair.
|
|
||||||
Allow lvconvert cache pools' data and metadata LV to raid.
|
|
||||||
Fix reading of old metadata with missing cache policy or mode settings.
|
|
||||||
Issue error if external_device_info_source=udev and udev db record incomplete.
|
|
||||||
Update lvmetad duplicate VG name handling to use hash function extensions.
|
|
||||||
Detect invalid vgrenames by vgid where the name is unchanged.
|
|
||||||
Fix passing of 32bit values through daemons (mostly lvmlockd).
|
|
||||||
Use local memory pool for whole alloc_handle manipulation.
|
|
||||||
Add missing pointer validation after dm_get_next_target().
|
|
||||||
Do not deref NULL pointer in debug message for _match_pv_tags().
|
|
||||||
Drop unneeded stat() call when checking for sysfs file.
|
|
||||||
Fix memory leak on error path of failing thin-pool percentage check.
|
|
||||||
Add missing test for failing node allocation in lvmetad.
|
|
||||||
Correct configure messages when enabling/disabling lvmlockd.
|
|
||||||
|
|
||||||
Version 2.02.134 - 9th November 2015
|
|
||||||
====================================
|
|
||||||
Refactor some lvmetad code and adjust some duplicate PV messages.
|
|
||||||
No longer repair/wipe VG/PVs if inaccessible because foreign or shared.
|
|
||||||
Pass correct data size to mirror log calc so log can be bigger than 1 extent.
|
|
||||||
|
|
||||||
Version 2.02.133 - 30th October 2015
|
|
||||||
====================================
|
|
||||||
Support repeated -o|--options for reporting commands.
|
|
||||||
Support -o- and -o# for reporting commands to remove and compact fields.
|
|
||||||
Fix missing PVs from pvs output if vgremove is run concurrently.
|
|
||||||
Remove unwanted error message when running pvs/vgs/lvs and vgremove at once.
|
|
||||||
Check newly created VG's metadata do not overlap in metadata ring buffer.
|
|
||||||
Check metadata area size is at least the minimum size defined for the format.
|
|
||||||
Thin pool targets uses low_water_mark from profile.
|
|
||||||
Dropping 'yet' from error of unsupported thick snapshot of snapshots.
|
|
||||||
Do not support unpartitioned DASD devices with CDL formatted with pvcreate.
|
|
||||||
For thins use flush for suspend only when volume size is reduced.
|
|
||||||
Enable code which detects the need of flush during suspend.
|
|
||||||
Ensure --use-policy will resize volume to fit below threshold.
|
|
||||||
Correct percentage evaluation when checking thin-pool over threshold.
|
|
||||||
Fix lvmcache to move PV from VG to orphans if VG is removed and lvmetad used.
|
|
||||||
Fix lvmcache to not cache even invalid info about PV which got removed.
|
|
||||||
Support checking of memlock daemon counter.
|
|
||||||
Allow all log levels to be used with the lvmetad -l option.
|
|
||||||
Add optional shutdown when idle support for lvmetad.
|
|
||||||
Fix missing in-sync progress info while lvconvert used with lvmpolld.
|
|
||||||
Add report/compact_output_cols to lvm.conf to define report cols to compact.
|
|
||||||
Do not change logging in lvm2 library when it's already set.
|
|
||||||
Check for enough space in thin-pool in command before creating new thin.
|
|
||||||
Make libblkid detect all copies of the same signature if use_blkid_wiping=1.
|
|
||||||
Fix vgimportclone with -n to not add number unnecessarily to base VG name.
|
|
||||||
Cleanup vgimportclone script and remove dependency on awk, grep, cut and tr.
|
|
||||||
Add vg_missing_pv_count report field to report number of missing PVs in a VG.
|
|
||||||
Properly identify internal LV holding sanlock locks within lv_role field.
|
|
||||||
Add metadata_devices and seg_metadata_le_ranges report fields for raid vols.
|
|
||||||
Fix lvm2-{activation,clvmd,cmirrord,monitor} service to exec before mounting.
|
|
||||||
|
|
||||||
Version 2.02.132 - 22nd September 2015
|
|
||||||
======================================
|
|
||||||
Fix lvmconf to set locking_type=2 if external locking library is requested.
|
|
||||||
Remove verbose message when rescanning an unchanged device. (2.02.119)
|
|
||||||
Add origin_uuid, mirror_log_uuid, move_pv_uuid, convert_lv_uuid report fields.
|
|
||||||
Add pool_lv_uuid, metadata_lv_uuid, data_lv_uuid reporting fields.
|
|
||||||
Fix PV label processing failure after pvcreate in lvm shell with lvmetad.
|
|
||||||
|
|
||||||
Version 2.02.131 - 15th September 2015
|
|
||||||
======================================
|
|
||||||
Rename 'make install_full_man' to install_all_man and add all_man target.
|
|
||||||
Fix vgimportclone cache_dir path name (2.02.115).
|
|
||||||
Swapping of LV identifiers handles more complex LVs.
|
|
||||||
Use passed list of PVS when allocating space in lvconvert --thinpool.
|
|
||||||
Disallow usage of --stripe and --stripesize when creating cache pool.
|
|
||||||
Warn user when caching raid or thin pool data LV.
|
|
||||||
When layering LV, move LV flags with segments.
|
|
||||||
Ignore persistent cache if configuration changed. (2.02.127)
|
|
||||||
Fix devices/filter to be applied before disk-accessing filters. (2.02.112)
|
|
||||||
Make tags only when requested via 'make tags'.
|
|
||||||
Configure supports --disable-dependency-tracking for one-time builds.
|
|
||||||
Fix usage of configure.h when building in srcdir != builddir.
|
|
||||||
|
|
||||||
Version 2.02.130 - 5th September 2015
|
|
||||||
=====================================
|
|
||||||
Fix use of uninitialized device status if reading outdated .cache record.
|
|
||||||
Restore support for --monitor option in lvcreate (2.02.112).
|
|
||||||
Read thin-pool data and metadata percent without flush.
|
|
||||||
Detect blocked thin-pool and avoid scanning their thin volumes.
|
|
||||||
Check if dm device is usable before checking its size (2.02.116).
|
|
||||||
Extend parsing of cache_check version in configure.
|
|
||||||
Make lvpoll error messages visible in lvmpolld's stderr and in syslog.
|
|
||||||
Add 'make install_full_man' to install all man pages regardless of config.
|
|
||||||
|
|
||||||
Version 2.02.129 - 26th August 2015
|
|
||||||
===================================
|
|
||||||
Drop error message when vgdisplay encounters an exported VG. (2.02.27)
|
|
||||||
Fix shared library generation to stop exporting internal functions.(2.02.120)
|
|
||||||
Accept --cachemode with lvconvert.
|
|
||||||
Fix and improve reporting properties of cache-pool.
|
|
||||||
Enable usage of --cachepolicy and --cachesetting with lvconvert.
|
|
||||||
Don't allow to reduce size of thin-pool metadata.
|
|
||||||
Fix debug buffer overflows in cmirrord logging.
|
|
||||||
Add --foreground and --help to cmirrord.
|
|
||||||
|
|
||||||
Version 2.02.128 - 17th August 2015
|
|
||||||
===================================
|
|
||||||
Allocation setting cache_pool_cachemode is replaced by cache_mode.
|
|
||||||
Don't attempt to close config file that couldn't be opened.
|
|
||||||
Check for valid cache mode in validation of cache segment.
|
|
||||||
Change internal interface handling cache mode and policy.
|
|
||||||
When no cache policy specified, prefer smq (if available) over mq.
|
|
||||||
Add demo cache-mq and cache-smq profiles.
|
|
||||||
Add cmd profilable allocation/cache_policy,cache_settings,cache_mode.
|
|
||||||
Require cache_check 0.5.4 for use of --clear-needs-check-flag.
|
|
||||||
Fix lvmetad udev rules to not override SYSTEMD_WANTS, add the service instead.
|
|
||||||
|
|
||||||
Version 2.02.127 - 10th August 2015
|
|
||||||
===================================
|
|
||||||
Do not init filters, locking, lvmetad, lvmpolld if command doesn't use it.
|
Do not init filters, locking, lvmetad, lvmpolld if command doesn't use it.
|
||||||
Order fields in struct cmd_context more logically.
|
Recognise vg/lv name format in dmsetup.
|
||||||
Add lock_type to lvmcache VG summary and info structs.
|
|
||||||
Fix regression in cache causing some PVs to bypass filters (2.02.105).
|
Fix regression in cache causing some PVs to bypass filters (2.02.105).
|
||||||
Make configure --enable-realtime the default now.
|
|
||||||
Update .gitignore and configure.in files to reflect usage of current tree.
|
|
||||||
|
|
||||||
Version 2.02.126 - 24th July 2015
|
Version 2.02.126 - 24th July 2015
|
||||||
=================================
|
=================================
|
||||||
|
|||||||
206
WHATS_NEW_DM
206
WHATS_NEW_DM
@@ -1,216 +1,22 @@
|
|||||||
Version 1.02.129 -
|
Version 1.02.104 -
|
||||||
=================================
|
=================================
|
||||||
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
|
|
||||||
=====================================
|
|
||||||
Use fully aligned allocations for dm_pool_strdup/strndup() (1.02.64).
|
|
||||||
Fix thin-pool table parameter feature order to match kernel output.
|
|
||||||
|
|
||||||
Version 1.02.115 - 25th January 2016
|
|
||||||
====================================
|
|
||||||
Fix man page for dmsetup udevcreatecookie.
|
|
||||||
|
|
||||||
Version 1.02.114 - 14th December 2015
|
|
||||||
=====================================
|
|
||||||
Better support for dmsetup static linkage.
|
|
||||||
Extend validity checks on dmeventd client socket.
|
|
||||||
|
|
||||||
Version 1.02.113 - 5th December 2015
|
|
||||||
====================================
|
|
||||||
Mirror plugin in dmeventd uses dm_get_status_mirror().
|
|
||||||
Add dm_get_status_mirror() for parsing mirror status line.
|
|
||||||
|
|
||||||
Version 1.02.112 - 28th November 2015
|
|
||||||
=====================================
|
|
||||||
Show error message when trying to create unsupported raid type.
|
|
||||||
Improve preloading sequence of an active thin-pool target.
|
|
||||||
Drop extra space from cache target line to fix unneded table reloads.
|
|
||||||
|
|
||||||
Version 1.02.111 - 23rd November 2015
|
|
||||||
=====================================
|
|
||||||
Extend dm_hash to support multiple values with the same key.
|
|
||||||
Add missing check for allocation inside dm_split_lvm_name().
|
|
||||||
Test dm_task_get_message_response for !NULL in dm_stats_print_region().
|
|
||||||
Add checks for failing dm_stats_create() in dmsetup.
|
|
||||||
Add missing fifo close when failed to initialize client connection.
|
|
||||||
|
|
||||||
Version 1.02.110 - 30th October 2015
|
|
||||||
====================================
|
|
||||||
Disable thin monitoring plugin when it fails too often (>10 times).
|
|
||||||
Fix/restore parsing of empty field '-' when processing dmeventd event.
|
|
||||||
Enhance dm_tree_node_size_changed() to recognize size reduction.
|
|
||||||
Support exit on idle for dmenventd (1 hour).
|
|
||||||
Add support to allow unmonitor device from plugin itself.
|
|
||||||
New design for thread co-operation in dmeventd.
|
|
||||||
Dmeventd read device status with 'noflush'.
|
|
||||||
Dmeventd closes control device when no device is monitored.
|
|
||||||
Thin plugin for dmeventd improved percentage usage.
|
|
||||||
Snapshot plugin for dmeventd improved percentage usage.
|
|
||||||
Add dm_hold_control_dev to allow holding of control device open.
|
|
||||||
Add dm_report_compact_given_fields to remove given empty fields from report.
|
|
||||||
Use libdm status parsing and local mem raid dmeventd plugin.
|
|
||||||
Use local mem pool and lock only lvm2 execution for mirror dmeventd plugin.
|
|
||||||
Lock protect only lvm2 execution for snapshot and thin dmeventd plugin.
|
|
||||||
Use local mempool for raid and mirror plugins.
|
|
||||||
Reworked thread initialization for dmeventd plugins.
|
|
||||||
Dmeventd handles snapshot overflow for now equally as invalid.
|
|
||||||
Convert dmeventd to use common logging macro system from libdm.
|
|
||||||
Return -ENOMEM when device registration fails instead of 0 (=success).
|
|
||||||
Enforce writethrough mode for cleaner policy.
|
|
||||||
Add support for recognition and deactivation of MD devices to blkdeactivate.
|
|
||||||
Move target status functions out of libdm-deptree.
|
|
||||||
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
|
|
||||||
======================================
|
|
||||||
Update man pages for dmsetup and dmstats.
|
|
||||||
Improve help text for dmsetup.
|
|
||||||
Use --noflush and --nolockfs when removing device with --force.
|
|
||||||
Parse new Overflow status string for snapshot target.
|
|
||||||
Check dir path components are valid if using dm_create_dir, error out if not.
|
|
||||||
Fix /dev/mapper handling to remove dangling entries if symlinks are found.
|
|
||||||
Make it possible to use blank value as selection for string list report field.
|
|
||||||
|
|
||||||
Version 1.02.108 - 15th September 2015
|
|
||||||
======================================
|
|
||||||
Do not check for full thin pool when activating without messages (1.02.107).
|
|
||||||
|
|
||||||
Version 1.02.107 - 5th September 2015
|
|
||||||
=====================================
|
|
||||||
Parse thin-pool status with one single routine internally.
|
|
||||||
Add --histogram to select default histogram fields for list and report.
|
|
||||||
Add report fields for displaying latency histogram configuration and data.
|
|
||||||
Add dmstats --bounds to specify histogram boundaries for a new region.
|
|
||||||
Add dm_histogram_to_string() to format histogram data in string form.
|
|
||||||
Add public methods to libdm to access numerical histogram config and data.
|
|
||||||
Parse and store histogram data in dm_stats_list() and dm_stats_populate().
|
|
||||||
Add an argument to specify histogram bounds to dm_stats_create_region().
|
|
||||||
Add dm_histogram_bounds_from_{string,uint64_t}() to parse histogram bounds.
|
|
||||||
Add dm_histogram handle type to represent a latency histogram and its bounds.
|
|
||||||
Fix devmapper.pc pkgconfig file to not reference non-existent rt.pc file.
|
|
||||||
Reinstate dm_task_get_info@Base to libdevmapper exports. (1.02.106)
|
|
||||||
|
|
||||||
Version 1.02.106 - 26th August 2015
|
|
||||||
===================================
|
|
||||||
Add 'precise' column to statistics reports.
|
|
||||||
Add --precise switch to 'dmstats create' to request nanosecond counters.
|
|
||||||
Add precise argument to dm_stats_create_region().
|
|
||||||
Add support to libdm-stats for precise_timestamps
|
|
||||||
|
|
||||||
Version 1.02.105 - 17th August 2015
|
|
||||||
===================================
|
|
||||||
Fix 'dmstats list -o all' segfault.
|
|
||||||
Separate dmstats statistics fields from region information fields.
|
|
||||||
Add interval and interval_ns fields to dmstats reports.
|
|
||||||
Do not include internal glibc headers in libdm-timestamp.c (1.02.104)
|
|
||||||
Exit immediately if no device is supplied to dmsetup wipe_table.
|
|
||||||
Suppress dmsetup report headings when no data is output. (1.02.104)
|
|
||||||
Adjust dmsetup usage/help output selection to match command invoked.
|
|
||||||
Fix dmsetup -o all to select correct fields in splitname report.
|
|
||||||
Restructure internal dmsetup argument handling across all commands.
|
|
||||||
Add dm_report_is_empty() to indicate there is no data awaiting output.
|
|
||||||
Add more arg validation for dm_tree_node_add_cache_target().
|
|
||||||
Add --alldevices switch to replace use of --force for stats create / delete.
|
|
||||||
|
|
||||||
Version 1.02.104 - 10th August 2015
|
|
||||||
===================================
|
|
||||||
Add dmstats.8 man page
|
Add dmstats.8 man page
|
||||||
Add dmstats --segments switch to create one region per device segment.
|
|
||||||
Add dmstats --regionid, --allregions to specify a single / all stats regions.
|
|
||||||
Add dmstats --allprograms for stats commands that filter by program ID.
|
|
||||||
Add dmstats --auxdata and --programid args to specify aux data and program ID.
|
|
||||||
Add report stats sub-command to provide repeating stats reports.
|
Add report stats sub-command to provide repeating stats reports.
|
||||||
Add clear, delete, list, and print stats sub-commands.
|
Add clear, delete, list, and print stats sub-commands.
|
||||||
Add create stats sub-command and --start, --length, --areas and --areasize.
|
Add create stats sub-command and --start, --length, --areas and --areasize.
|
||||||
Recognize 'dmstats' as an alias for 'dmsetup stats' when run with this name.
|
|
||||||
Add a 'stats' command to dmsetup to configure, manage and report stats data.
|
Add a 'stats' command to dmsetup to configure, manage and report stats data.
|
||||||
Add statistics fields to dmsetup -o.
|
Add --regionid, --allregions to specify a single stats region or all regions.
|
||||||
|
Add --allprograms for stats commands that filter by program ID.
|
||||||
|
Add --auxdata and --programid arguments to set stats aux data and program ID.
|
||||||
|
Add statistics fields to -o <field>
|
||||||
Add libdm-stats library to allow management of device-mapper statistics.
|
Add libdm-stats library to allow management of device-mapper statistics.
|
||||||
Add --nosuffix to suppress dmsetup unit suffixes in report output.
|
Add --units to control report field output units.
|
||||||
Add --units to control dmsetup report field output units.
|
|
||||||
Add support to redisplay column headings for repeating column reports.
|
Add support to redisplay column headings for repeating column reports.
|
||||||
Fix report header and row resource leaks.
|
Fix report header and row resource leaks.
|
||||||
Report timestamps of ioctls with dmsetup -vvv.
|
Report timestamps of ioctls with dmsetup -vvv.
|
||||||
Recognize report field name variants without any underscores too.
|
Recognize report field name variants without any underscores too.
|
||||||
Add dmsetup --interval and --count to repeat reports at specified intervals.
|
Add dmsetup --interval and --count to repeat reports at specified intervals.
|
||||||
Add dm_timestamp functions to libdevmapper.
|
Add dm_timestamp functions to libdevmapper.
|
||||||
Recognise vg/lv name format in dmsetup.
|
|
||||||
Move size display code to libdevmapper as dm_size_to_string.
|
|
||||||
|
|
||||||
Version 1.02.103 - 24th July 2015
|
Version 1.02.103 - 24th July 2015
|
||||||
=================================
|
=================================
|
||||||
|
|||||||
309
aclocal.m4
vendored
309
aclocal.m4
vendored
@@ -12,63 +12,6 @@
|
|||||||
# PARTICULAR PURPOSE.
|
# PARTICULAR PURPOSE.
|
||||||
|
|
||||||
m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
|
m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
|
||||||
# ===========================================================================
|
|
||||||
# http://www.gnu.org/software/autoconf-archive/ax_python_module.html
|
|
||||||
# ===========================================================================
|
|
||||||
#
|
|
||||||
# SYNOPSIS
|
|
||||||
#
|
|
||||||
# AX_PYTHON_MODULE(modname[, fatal, python])
|
|
||||||
#
|
|
||||||
# DESCRIPTION
|
|
||||||
#
|
|
||||||
# Checks for Python module.
|
|
||||||
#
|
|
||||||
# If fatal is non-empty then absence of a module will trigger an error.
|
|
||||||
# The third parameter can either be "python" for Python 2 or "python3" for
|
|
||||||
# Python 3; defaults to Python 3.
|
|
||||||
#
|
|
||||||
# LICENSE
|
|
||||||
#
|
|
||||||
# Copyright (c) 2008 Andrew Collier
|
|
||||||
#
|
|
||||||
# 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 8
|
|
||||||
|
|
||||||
AU_ALIAS([AC_PYTHON_MODULE], [AX_PYTHON_MODULE])
|
|
||||||
AC_DEFUN([AX_PYTHON_MODULE],[
|
|
||||||
if test -z $PYTHON;
|
|
||||||
then
|
|
||||||
if test -z "$3";
|
|
||||||
then
|
|
||||||
PYTHON="python3"
|
|
||||||
else
|
|
||||||
PYTHON="$3"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
PYTHON_NAME=`basename $PYTHON`
|
|
||||||
AC_MSG_CHECKING($PYTHON_NAME module: $1)
|
|
||||||
$PYTHON -c "import $1" 2>/dev/null
|
|
||||||
if test $? -eq 0;
|
|
||||||
then
|
|
||||||
AC_MSG_RESULT(yes)
|
|
||||||
eval AS_TR_CPP(HAVE_PYMOD_$1)=yes
|
|
||||||
else
|
|
||||||
AC_MSG_RESULT(no)
|
|
||||||
eval AS_TR_CPP(HAVE_PYMOD_$1)=no
|
|
||||||
#
|
|
||||||
if test -n "$2"
|
|
||||||
then
|
|
||||||
AC_MSG_ERROR(failed to find required module $1)
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
])
|
|
||||||
|
|
||||||
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||||||
# serial 1 (pkg-config-0.24)
|
# serial 1 (pkg-config-0.24)
|
||||||
#
|
#
|
||||||
@@ -284,256 +227,4 @@ AS_VAR_COPY([$1], [pkg_cv_][$1])
|
|||||||
AS_VAR_IF([$1], [""], [$5], [$4])dnl
|
AS_VAR_IF([$1], [""], [$5], [$4])dnl
|
||||||
])# PKG_CHECK_VAR
|
])# PKG_CHECK_VAR
|
||||||
|
|
||||||
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
|
|
||||||
#
|
|
||||||
# This file is free software; the Free Software Foundation
|
|
||||||
# gives unlimited permission to copy and/or distribute it,
|
|
||||||
# with or without modifications, as long as this notice is preserved.
|
|
||||||
|
|
||||||
|
|
||||||
# AM_PATH_PYTHON([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
# Adds support for distributing Python modules and packages. To
|
|
||||||
# install modules, copy them to $(pythondir), using the python_PYTHON
|
|
||||||
# automake variable. To install a package with the same name as the
|
|
||||||
# automake package, install to $(pkgpythondir), or use the
|
|
||||||
# pkgpython_PYTHON automake variable.
|
|
||||||
#
|
|
||||||
# The variables $(pyexecdir) and $(pkgpyexecdir) are provided as
|
|
||||||
# locations to install python extension modules (shared libraries).
|
|
||||||
# Another macro is required to find the appropriate flags to compile
|
|
||||||
# extension modules.
|
|
||||||
#
|
|
||||||
# If your package is configured with a different prefix to python,
|
|
||||||
# users will have to add the install directory to the PYTHONPATH
|
|
||||||
# environment variable, or create a .pth file (see the python
|
|
||||||
# documentation for details).
|
|
||||||
#
|
|
||||||
# If the MINIMUM-VERSION argument is passed, AM_PATH_PYTHON will
|
|
||||||
# cause an error if the version of python installed on the system
|
|
||||||
# doesn't meet the requirement. MINIMUM-VERSION should consist of
|
|
||||||
# numbers and dots only.
|
|
||||||
AC_DEFUN([AM_PATH_PYTHON],
|
|
||||||
[
|
|
||||||
dnl Find a Python interpreter. Python versions prior to 2.0 are not
|
|
||||||
dnl supported. (2.0 was released on October 16, 2000).
|
|
||||||
m4_define_default([_AM_PYTHON_INTERPRETER_LIST],
|
|
||||||
[python python2 python3 python3.3 python3.2 python3.1 python3.0 python2.7 dnl
|
|
||||||
python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0])
|
|
||||||
|
|
||||||
AC_ARG_VAR([PYTHON], [the Python interpreter])
|
|
||||||
|
|
||||||
m4_if([$1],[],[
|
|
||||||
dnl No version check is needed.
|
|
||||||
# Find any Python interpreter.
|
|
||||||
if test -z "$PYTHON"; then
|
|
||||||
AC_PATH_PROGS([PYTHON], _AM_PYTHON_INTERPRETER_LIST, :)
|
|
||||||
fi
|
|
||||||
am_display_PYTHON=python
|
|
||||||
], [
|
|
||||||
dnl A version check is needed.
|
|
||||||
if test -n "$PYTHON"; then
|
|
||||||
# If the user set $PYTHON, use it and don't search something else.
|
|
||||||
AC_MSG_CHECKING([whether $PYTHON version is >= $1])
|
|
||||||
AM_PYTHON_CHECK_VERSION([$PYTHON], [$1],
|
|
||||||
[AC_MSG_RESULT([yes])],
|
|
||||||
[AC_MSG_RESULT([no])
|
|
||||||
AC_MSG_ERROR([Python interpreter is too old])])
|
|
||||||
am_display_PYTHON=$PYTHON
|
|
||||||
else
|
|
||||||
# Otherwise, try each interpreter until we find one that satisfies
|
|
||||||
# VERSION.
|
|
||||||
AC_CACHE_CHECK([for a Python interpreter with version >= $1],
|
|
||||||
[am_cv_pathless_PYTHON],[
|
|
||||||
for am_cv_pathless_PYTHON in _AM_PYTHON_INTERPRETER_LIST none; do
|
|
||||||
test "$am_cv_pathless_PYTHON" = none && break
|
|
||||||
AM_PYTHON_CHECK_VERSION([$am_cv_pathless_PYTHON], [$1], [break])
|
|
||||||
done])
|
|
||||||
# Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON.
|
|
||||||
if test "$am_cv_pathless_PYTHON" = none; then
|
|
||||||
PYTHON=:
|
|
||||||
else
|
|
||||||
AC_PATH_PROG([PYTHON], [$am_cv_pathless_PYTHON])
|
|
||||||
fi
|
|
||||||
am_display_PYTHON=$am_cv_pathless_PYTHON
|
|
||||||
fi
|
|
||||||
])
|
|
||||||
|
|
||||||
if test "$PYTHON" = :; then
|
|
||||||
dnl Run any user-specified action, or abort.
|
|
||||||
m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])])
|
|
||||||
else
|
|
||||||
|
|
||||||
dnl Query Python for its version number. Getting [:3] seems to be
|
|
||||||
dnl the best way to do this; it's what "site.py" does in the standard
|
|
||||||
dnl library.
|
|
||||||
|
|
||||||
AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version],
|
|
||||||
[am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[[:3]])"`])
|
|
||||||
AC_SUBST([PYTHON_VERSION], [$am_cv_python_version])
|
|
||||||
|
|
||||||
dnl Use the values of $prefix and $exec_prefix for the corresponding
|
|
||||||
dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX. These are made
|
|
||||||
dnl distinct variables so they can be overridden if need be. However,
|
|
||||||
dnl general consensus is that you shouldn't need this ability.
|
|
||||||
|
|
||||||
AC_SUBST([PYTHON_PREFIX], ['${prefix}'])
|
|
||||||
AC_SUBST([PYTHON_EXEC_PREFIX], ['${exec_prefix}'])
|
|
||||||
|
|
||||||
dnl At times (like when building shared libraries) you may want
|
|
||||||
dnl to know which OS platform Python thinks this is.
|
|
||||||
|
|
||||||
AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform],
|
|
||||||
[am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`])
|
|
||||||
AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform])
|
|
||||||
|
|
||||||
# Just factor out some code duplication.
|
|
||||||
am_python_setup_sysconfig="\
|
|
||||||
import sys
|
|
||||||
# Prefer sysconfig over distutils.sysconfig, for better compatibility
|
|
||||||
# with python 3.x. See automake bug#10227.
|
|
||||||
try:
|
|
||||||
import sysconfig
|
|
||||||
except ImportError:
|
|
||||||
can_use_sysconfig = 0
|
|
||||||
else:
|
|
||||||
can_use_sysconfig = 1
|
|
||||||
# Can't use sysconfig in CPython 2.7, since it's broken in virtualenvs:
|
|
||||||
# <https://github.com/pypa/virtualenv/issues/118>
|
|
||||||
try:
|
|
||||||
from platform import python_implementation
|
|
||||||
if python_implementation() == 'CPython' and sys.version[[:3]] == '2.7':
|
|
||||||
can_use_sysconfig = 0
|
|
||||||
except ImportError:
|
|
||||||
pass"
|
|
||||||
|
|
||||||
dnl Set up 4 directories:
|
|
||||||
|
|
||||||
dnl pythondir -- where to install python scripts. This is the
|
|
||||||
dnl site-packages directory, not the python standard library
|
|
||||||
dnl directory like in previous automake betas. This behavior
|
|
||||||
dnl is more consistent with lispdir.m4 for example.
|
|
||||||
dnl Query distutils for this directory.
|
|
||||||
AC_CACHE_CHECK([for $am_display_PYTHON script directory],
|
|
||||||
[am_cv_python_pythondir],
|
|
||||||
[if test "x$prefix" = xNONE
|
|
||||||
then
|
|
||||||
am_py_prefix=$ac_default_prefix
|
|
||||||
else
|
|
||||||
am_py_prefix=$prefix
|
|
||||||
fi
|
|
||||||
am_cv_python_pythondir=`$PYTHON -c "
|
|
||||||
$am_python_setup_sysconfig
|
|
||||||
if can_use_sysconfig:
|
|
||||||
sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'})
|
|
||||||
else:
|
|
||||||
from distutils import sysconfig
|
|
||||||
sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix')
|
|
||||||
sys.stdout.write(sitedir)"`
|
|
||||||
case $am_cv_python_pythondir in
|
|
||||||
$am_py_prefix*)
|
|
||||||
am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'`
|
|
||||||
am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"`
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
case $am_py_prefix in
|
|
||||||
/usr|/System*) ;;
|
|
||||||
*)
|
|
||||||
am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
])
|
|
||||||
AC_SUBST([pythondir], [$am_cv_python_pythondir])
|
|
||||||
|
|
||||||
dnl pkgpythondir -- $PACKAGE directory under pythondir. Was
|
|
||||||
dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is
|
|
||||||
dnl more consistent with the rest of automake.
|
|
||||||
|
|
||||||
AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE])
|
|
||||||
|
|
||||||
dnl pyexecdir -- directory for installing python extension modules
|
|
||||||
dnl (shared libraries)
|
|
||||||
dnl Query distutils for this directory.
|
|
||||||
AC_CACHE_CHECK([for $am_display_PYTHON extension module directory],
|
|
||||||
[am_cv_python_pyexecdir],
|
|
||||||
[if test "x$exec_prefix" = xNONE
|
|
||||||
then
|
|
||||||
am_py_exec_prefix=$am_py_prefix
|
|
||||||
else
|
|
||||||
am_py_exec_prefix=$exec_prefix
|
|
||||||
fi
|
|
||||||
am_cv_python_pyexecdir=`$PYTHON -c "
|
|
||||||
$am_python_setup_sysconfig
|
|
||||||
if can_use_sysconfig:
|
|
||||||
sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_prefix'})
|
|
||||||
else:
|
|
||||||
from distutils import sysconfig
|
|
||||||
sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_prefix')
|
|
||||||
sys.stdout.write(sitedir)"`
|
|
||||||
case $am_cv_python_pyexecdir in
|
|
||||||
$am_py_exec_prefix*)
|
|
||||||
am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'`
|
|
||||||
am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"`
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
case $am_py_exec_prefix in
|
|
||||||
/usr|/System*) ;;
|
|
||||||
*)
|
|
||||||
am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
])
|
|
||||||
AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir])
|
|
||||||
|
|
||||||
dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE)
|
|
||||||
|
|
||||||
AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE])
|
|
||||||
|
|
||||||
dnl Run any user-specified action.
|
|
||||||
$2
|
|
||||||
fi
|
|
||||||
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
# AM_PYTHON_CHECK_VERSION(PROG, VERSION, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
# Run ACTION-IF-TRUE if the Python interpreter PROG has version >= VERSION.
|
|
||||||
# Run ACTION-IF-FALSE otherwise.
|
|
||||||
# This test uses sys.hexversion instead of the string equivalent (first
|
|
||||||
# word of sys.version), in order to cope with versions such as 2.2c1.
|
|
||||||
# This supports Python 2.0 or higher. (2.0 was released on October 16, 2000).
|
|
||||||
AC_DEFUN([AM_PYTHON_CHECK_VERSION],
|
|
||||||
[prog="import sys
|
|
||||||
# split strings by '.' and convert to numeric. Append some zeros
|
|
||||||
# because we need at least 4 digits for the hex conversion.
|
|
||||||
# map returns an iterator in Python 3.0 and a list in 2.x
|
|
||||||
minver = list(map(int, '$2'.split('.'))) + [[0, 0, 0]]
|
|
||||||
minverhex = 0
|
|
||||||
# xrange is not present in Python 3.0 and range returns an iterator
|
|
||||||
for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]]
|
|
||||||
sys.exit(sys.hexversion < minverhex)"
|
|
||||||
AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])])
|
|
||||||
|
|
||||||
# Copyright (C) 2001-2014 Free Software Foundation, Inc.
|
|
||||||
#
|
|
||||||
# This file is free software; the Free Software Foundation
|
|
||||||
# gives unlimited permission to copy and/or distribute it,
|
|
||||||
# with or without modifications, as long as this notice is preserved.
|
|
||||||
|
|
||||||
# AM_RUN_LOG(COMMAND)
|
|
||||||
# -------------------
|
|
||||||
# Run COMMAND, save the exit status in ac_status, and log it.
|
|
||||||
# (This has been adapted from Autoconf's _AC_RUN_LOG macro.)
|
|
||||||
AC_DEFUN([AM_RUN_LOG],
|
|
||||||
[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD
|
|
||||||
($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
|
|
||||||
ac_status=$?
|
|
||||||
echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
|
|
||||||
(exit $ac_status); }])
|
|
||||||
|
|
||||||
m4_include([acinclude.m4])
|
m4_include([acinclude.m4])
|
||||||
|
|||||||
@@ -1,170 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
# py-compile - Compile a Python program
|
|
||||||
|
|
||||||
scriptversion=2011-06-08.12; # UTC
|
|
||||||
|
|
||||||
# Copyright (C) 2000-2014 Free Software Foundation, Inc.
|
|
||||||
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation; either version 2, or (at your option)
|
|
||||||
# any later version.
|
|
||||||
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
# As a special exception to the GNU General Public License, if you
|
|
||||||
# distribute this file as part of a program that contains a
|
|
||||||
# configuration script generated by Autoconf, you may include it under
|
|
||||||
# the same distribution terms that you use for the rest of that program.
|
|
||||||
|
|
||||||
# This file is maintained in Automake, please report
|
|
||||||
# bugs to <bug-automake@gnu.org> or send patches to
|
|
||||||
# <automake-patches@gnu.org>.
|
|
||||||
|
|
||||||
if [ -z "$PYTHON" ]; then
|
|
||||||
PYTHON=python
|
|
||||||
fi
|
|
||||||
|
|
||||||
me=py-compile
|
|
||||||
|
|
||||||
usage_error ()
|
|
||||||
{
|
|
||||||
echo "$me: $*" >&2
|
|
||||||
echo "Try '$me --help' for more information." >&2
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
basedir=
|
|
||||||
destdir=
|
|
||||||
while test $# -ne 0; do
|
|
||||||
case "$1" in
|
|
||||||
--basedir)
|
|
||||||
if test $# -lt 2; then
|
|
||||||
usage_error "option '--basedir' requires an argument"
|
|
||||||
else
|
|
||||||
basedir=$2
|
|
||||||
fi
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
--destdir)
|
|
||||||
if test $# -lt 2; then
|
|
||||||
usage_error "option '--destdir' requires an argument"
|
|
||||||
else
|
|
||||||
destdir=$2
|
|
||||||
fi
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-h|--help)
|
|
||||||
cat <<\EOF
|
|
||||||
Usage: py-compile [--help] [--version] [--basedir DIR] [--destdir DIR] FILES..."
|
|
||||||
|
|
||||||
Byte compile some python scripts FILES. Use --destdir to specify any
|
|
||||||
leading directory path to the FILES that you don't want to include in the
|
|
||||||
byte compiled file. Specify --basedir for any additional path information you
|
|
||||||
do want to be shown in the byte compiled file.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
py-compile --destdir /tmp/pkg-root --basedir /usr/share/test test.py test2.py
|
|
||||||
|
|
||||||
Report bugs to <bug-automake@gnu.org>.
|
|
||||||
EOF
|
|
||||||
exit $?
|
|
||||||
;;
|
|
||||||
-v|--version)
|
|
||||||
echo "$me $scriptversion"
|
|
||||||
exit $?
|
|
||||||
;;
|
|
||||||
--)
|
|
||||||
shift
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
-*)
|
|
||||||
usage_error "unrecognized option '$1'"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
|
|
||||||
files=$*
|
|
||||||
if test -z "$files"; then
|
|
||||||
usage_error "no files given"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# if basedir was given, then it should be prepended to filenames before
|
|
||||||
# byte compilation.
|
|
||||||
if [ -z "$basedir" ]; then
|
|
||||||
pathtrans="path = file"
|
|
||||||
else
|
|
||||||
pathtrans="path = os.path.join('$basedir', file)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# if destdir was given, then it needs to be prepended to the filename to
|
|
||||||
# byte compile but not go into the compiled file.
|
|
||||||
if [ -z "$destdir" ]; then
|
|
||||||
filetrans="filepath = path"
|
|
||||||
else
|
|
||||||
filetrans="filepath = os.path.normpath('$destdir' + os.sep + path)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
$PYTHON -c "
|
|
||||||
import sys, os, py_compile, imp
|
|
||||||
|
|
||||||
files = '''$files'''
|
|
||||||
|
|
||||||
sys.stdout.write('Byte-compiling python modules...\n')
|
|
||||||
for file in files.split():
|
|
||||||
$pathtrans
|
|
||||||
$filetrans
|
|
||||||
if not os.path.exists(filepath) or not (len(filepath) >= 3
|
|
||||||
and filepath[-3:] == '.py'):
|
|
||||||
continue
|
|
||||||
sys.stdout.write(file)
|
|
||||||
sys.stdout.flush()
|
|
||||||
if hasattr(imp, 'get_tag'):
|
|
||||||
py_compile.compile(filepath, imp.cache_from_source(filepath), path)
|
|
||||||
else:
|
|
||||||
py_compile.compile(filepath, filepath + 'c', path)
|
|
||||||
sys.stdout.write('\n')" || exit $?
|
|
||||||
|
|
||||||
# this will fail for python < 1.5, but that doesn't matter ...
|
|
||||||
$PYTHON -O -c "
|
|
||||||
import sys, os, py_compile, imp
|
|
||||||
|
|
||||||
# pypy does not use .pyo optimization
|
|
||||||
if hasattr(sys, 'pypy_translation_info'):
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
files = '''$files'''
|
|
||||||
sys.stdout.write('Byte-compiling python modules (optimized versions) ...\n')
|
|
||||||
for file in files.split():
|
|
||||||
$pathtrans
|
|
||||||
$filetrans
|
|
||||||
if not os.path.exists(filepath) or not (len(filepath) >= 3
|
|
||||||
and filepath[-3:] == '.py'):
|
|
||||||
continue
|
|
||||||
sys.stdout.write(file)
|
|
||||||
sys.stdout.flush()
|
|
||||||
if hasattr(imp, 'get_tag'):
|
|
||||||
py_compile.compile(filepath, imp.cache_from_source(filepath, False), path)
|
|
||||||
else:
|
|
||||||
py_compile.compile(filepath, filepath + 'o', path)
|
|
||||||
sys.stdout.write('\n')" 2>/dev/null || :
|
|
||||||
|
|
||||||
# Local Variables:
|
|
||||||
# mode: shell-script
|
|
||||||
# sh-indentation: 2
|
|
||||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
|
||||||
# time-stamp-start: "scriptversion="
|
|
||||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
|
||||||
# time-stamp-time-zone: "UTC"
|
|
||||||
# time-stamp-end: "; # UTC"
|
|
||||||
# End:
|
|
||||||
2
conf/.gitignore
vendored
2
conf/.gitignore
vendored
@@ -2,5 +2,3 @@ command_profile_template.profile
|
|||||||
example.conf
|
example.conf
|
||||||
lvmlocal.conf
|
lvmlocal.conf
|
||||||
metadata_profile_template.profile
|
metadata_profile_template.profile
|
||||||
configure.h
|
|
||||||
lvm-version.h
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
|
# Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
|
||||||
#
|
#
|
||||||
# This file is part of LVM2.
|
# This file is part of LVM2.
|
||||||
#
|
#
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program; if not, write to the Free Software Foundation,
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
srcdir = @srcdir@
|
srcdir = @srcdir@
|
||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
@@ -20,11 +20,7 @@ CONFDEST=lvm.conf
|
|||||||
CONFLOCAL=lvmlocal.conf
|
CONFLOCAL=lvmlocal.conf
|
||||||
|
|
||||||
PROFILE_TEMPLATES=command_profile_template.profile metadata_profile_template.profile
|
PROFILE_TEMPLATES=command_profile_template.profile metadata_profile_template.profile
|
||||||
PROFILES=$(PROFILE_TEMPLATES) \
|
PROFILES=$(PROFILE_TEMPLATES) $(srcdir)/thin-generic.profile $(srcdir)/thin-performance.profile
|
||||||
$(srcdir)/cache-mq.profile \
|
|
||||||
$(srcdir)/cache-smq.profile \
|
|
||||||
$(srcdir)/thin-generic.profile \
|
|
||||||
$(srcdir)/thin-performance.profile
|
|
||||||
|
|
||||||
include $(top_builddir)/make.tmpl
|
include $(top_builddir)/make.tmpl
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
# Demo configuration 'mq' cache policy
|
|
||||||
#
|
|
||||||
# Note: This policy has been deprecated in favor of the smq policy
|
|
||||||
# keyword "default" means, setting is left with kernel defaults.
|
|
||||||
#
|
|
||||||
|
|
||||||
allocation {
|
|
||||||
cache_pool_chunk_size = 64
|
|
||||||
cache_mode = "writethrough"
|
|
||||||
cache_policy = "mq"
|
|
||||||
cache_settings {
|
|
||||||
mq {
|
|
||||||
sequential_threshold = "default" # #nr_sequential_ios
|
|
||||||
random_threshold = "default" # #nr_random_ios
|
|
||||||
read_promote_adjustment = "default"
|
|
||||||
write_promote_adjustment = "default"
|
|
||||||
discard_promote_adjustment = "default"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
# Demo configuration 'smq' cache policy
|
|
||||||
#
|
|
||||||
# The stochastic multi-queue (smq) policy addresses some of the problems
|
|
||||||
# with the multiqueue (mq) policy and uses less memory.
|
|
||||||
#
|
|
||||||
|
|
||||||
allocation {
|
|
||||||
cache_pool_chunk_size = 64
|
|
||||||
cache_mode = "writethrough"
|
|
||||||
cache_policy = "smq"
|
|
||||||
cache_settings {
|
|
||||||
# currently no settins for "smq" policy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -11,17 +11,6 @@
|
|||||||
# Refer to 'man lvm.conf' for further information about profiles and
|
# Refer to 'man lvm.conf' for further information about profiles and
|
||||||
# general configuration file layout.
|
# general configuration file layout.
|
||||||
#
|
#
|
||||||
allocation {
|
|
||||||
cache_mode="writethrough"
|
|
||||||
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 {
|
global {
|
||||||
units="h"
|
units="h"
|
||||||
si_unit_consistency=1
|
si_unit_consistency=1
|
||||||
@@ -29,9 +18,7 @@ global {
|
|||||||
lvdisplay_shows_full_device_path=0
|
lvdisplay_shows_full_device_path=0
|
||||||
}
|
}
|
||||||
report {
|
report {
|
||||||
output_format="basic"
|
|
||||||
compact_output=0
|
compact_output=0
|
||||||
compact_output_cols=""
|
|
||||||
aligned=1
|
aligned=1
|
||||||
buffered=1
|
buffered=1
|
||||||
headings=1
|
headings=1
|
||||||
@@ -41,7 +28,6 @@ report {
|
|||||||
quoted=1
|
quoted=1
|
||||||
colums_as_rows=0
|
colums_as_rows=0
|
||||||
binary_values_as_numeric=0
|
binary_values_as_numeric=0
|
||||||
time_format="%Y-%m-%d %T %z"
|
|
||||||
devtypes_sort="devtype_name"
|
devtypes_sort="devtype_name"
|
||||||
devtypes_cols="devtype_name,devtype_max_partitions,devtype_description"
|
devtypes_cols="devtype_name,devtype_max_partitions,devtype_description"
|
||||||
devtypes_cols_verbose="devtype_name,devtype_max_partitions,devtype_description"
|
devtypes_cols_verbose="devtype_name,devtype_max_partitions,devtype_description"
|
||||||
@@ -60,15 +46,4 @@ report {
|
|||||||
pvsegs_sort="pv_name,pvseg_start"
|
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="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"
|
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
|
|
||||||
}
|
}
|
||||||
|
|||||||
1908
conf/example.conf.in
1908
conf/example.conf.in
File diff suppressed because it is too large
Load Diff
@@ -24,34 +24,34 @@ local {
|
|||||||
|
|
||||||
# Configuration option local/system_id.
|
# Configuration option local/system_id.
|
||||||
# Defines the local system ID for lvmlocal mode.
|
# Defines the local system ID for lvmlocal mode.
|
||||||
# This is used when global/system_id_source is set to 'lvmlocal' in the
|
# This is used when global/system_id_source is set
|
||||||
# main configuration file, e.g. lvm.conf. When used, it must be set to
|
# to 'lvmlocal' in the main configuration file,
|
||||||
# a unique value among all hosts sharing access to the storage,
|
# e.g. lvm.conf.
|
||||||
|
# When used, it must be set to a unique value
|
||||||
|
# among all hosts sharing access to the storage,
|
||||||
# e.g. a host name.
|
# e.g. a host name.
|
||||||
#
|
# Example:
|
||||||
# Example
|
# Set no system ID.
|
||||||
# Set no system ID:
|
|
||||||
# system_id = ""
|
# system_id = ""
|
||||||
# Set the system_id to a specific name:
|
# Example:
|
||||||
|
# Set the system_id to the string 'host1'.
|
||||||
# system_id = "host1"
|
# system_id = "host1"
|
||||||
#
|
|
||||||
# This configuration option has an automatic default value.
|
|
||||||
# system_id = ""
|
# system_id = ""
|
||||||
|
|
||||||
# Configuration option local/extra_system_ids.
|
# Configuration option local/extra_system_ids.
|
||||||
# A list of extra VG system IDs the local host can access.
|
# A list of extra VG system IDs the local host can access.
|
||||||
# VGs with the system IDs listed here (in addition to the host's own
|
# VGs with the system IDs listed here (in addition
|
||||||
# system ID) can be fully accessed by the local host. (These are
|
# to the host's own system ID) can be fully accessed
|
||||||
# system IDs that the host sees in VGs, not system IDs that identify
|
# by the local host. (These are system IDs that the
|
||||||
# the local host, which is determined by system_id_source.)
|
# host sees in VGs, not system IDs that identify the
|
||||||
# Use this only after consulting 'man lvmsystemid' to be certain of
|
# local host, which is determined by system_id_source.)
|
||||||
# correct usage and possible dangers.
|
# Use this only after consulting 'man lvmsystemid'
|
||||||
|
# to be certain of correct usage and possible dangers.
|
||||||
# This configuration option does not have a default value defined.
|
# This configuration option does not have a default value defined.
|
||||||
|
|
||||||
# Configuration option local/host_id.
|
# Configuration option local/host_id.
|
||||||
# The lvmlockd sanlock host_id.
|
# The lvmlockd sanlock host_id.
|
||||||
# This must be unique among all hosts, and must be between 1 and 2000.
|
# This must be a unique among all hosts,
|
||||||
# Applicable only if LVM is compiled with lockd support
|
# and must be between 1 and 2000.
|
||||||
# This configuration option has an automatic default value.
|
|
||||||
# host_id = 0
|
# host_id = 0
|
||||||
}
|
}
|
||||||
|
|||||||
236
configure.in
236
configure.in
@@ -1,6 +1,6 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
## Copyright (C) 2000-2004 Sistina Software, Inc. All rights reserved.
|
## Copyright (C) 2000-2004 Sistina Software, Inc. All rights reserved.
|
||||||
## Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved.
|
## Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
|
||||||
##
|
##
|
||||||
## This copyrighted material is made available to anyone wishing to use,
|
## This copyrighted material is made available to anyone wishing to use,
|
||||||
## modify, copy, or redistribute it subject to the terms and conditions
|
## modify, copy, or redistribute it subject to the terms and conditions
|
||||||
@@ -8,15 +8,15 @@
|
|||||||
##
|
##
|
||||||
## You should have received a copy of the GNU General Public License
|
## You should have received a copy of the GNU General Public License
|
||||||
## along with this program; if not, write to the Free Software Foundation,
|
## along with this program; if not, write to the Free Software Foundation,
|
||||||
## Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
## Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
AC_PREREQ(2.69)
|
AC_PREREQ(2.61)
|
||||||
################################################################################
|
################################################################################
|
||||||
dnl -- Process this file with autoconf to produce a configure script.
|
dnl -- Process this file with autoconf to produce a configure script.
|
||||||
AC_INIT
|
AC_INIT
|
||||||
AC_CONFIG_SRCDIR([lib/device/dev-cache.h])
|
AC_CONFIG_SRCDIR([lib/device/dev-cache.h])
|
||||||
AC_CONFIG_HEADERS([include/configure.h])
|
AC_CONFIG_HEADERS([lib/misc/configure.h])
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
dnl -- Setup the directory where autoconf has auxilary files
|
dnl -- Setup the directory where autoconf has auxilary files
|
||||||
@@ -37,8 +37,9 @@ case "$host_os" in
|
|||||||
LDDEPS="$LDDEPS .export.sym"
|
LDDEPS="$LDDEPS .export.sym"
|
||||||
LIB_SUFFIX=so
|
LIB_SUFFIX=so
|
||||||
DEVMAPPER=yes
|
DEVMAPPER=yes
|
||||||
BUILD_LVMETAD=no
|
LVMETAD=no
|
||||||
BUILD_LVMPOLLD=no
|
LVMPOLLD=no
|
||||||
|
LVMLOCKD=no
|
||||||
LOCKDSANLOCK=no
|
LOCKDSANLOCK=no
|
||||||
LOCKDDLM=no
|
LOCKDDLM=no
|
||||||
ODIRECT=yes
|
ODIRECT=yes
|
||||||
@@ -85,7 +86,6 @@ AC_PROG_MKDIR_P
|
|||||||
AC_PROG_RANLIB
|
AC_PROG_RANLIB
|
||||||
AC_PATH_TOOL(CFLOW_CMD, cflow)
|
AC_PATH_TOOL(CFLOW_CMD, cflow)
|
||||||
AC_PATH_TOOL(CSCOPE_CMD, cscope)
|
AC_PATH_TOOL(CSCOPE_CMD, cscope)
|
||||||
AC_PATH_TOOL(CHMOD, chmod)
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
dnl -- Check for header files.
|
dnl -- Check for header files.
|
||||||
@@ -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 \
|
sys/time.h sys/types.h sys/utsname.h sys/wait.h time.h \
|
||||||
unistd.h], , [AC_MSG_ERROR(bailing out)])
|
unistd.h], , [AC_MSG_ERROR(bailing out)])
|
||||||
|
|
||||||
AC_CHECK_HEADERS(termios.h sys/statvfs.h sys/timerfd.h)
|
AC_CHECK_HEADERS(termios.h sys/statvfs.h)
|
||||||
|
|
||||||
case "$host_os" in
|
case "$host_os" in
|
||||||
linux*)
|
linux*)
|
||||||
@@ -155,15 +155,6 @@ AC_FUNC_STAT
|
|||||||
AC_FUNC_STRTOD
|
AC_FUNC_STRTOD
|
||||||
AC_FUNC_VPRINTF
|
AC_FUNC_VPRINTF
|
||||||
|
|
||||||
################################################################################
|
|
||||||
dnl -- Disable dependency tracking
|
|
||||||
AC_MSG_CHECKING(whether to enable dependency tracking)
|
|
||||||
AC_ARG_ENABLE(dependency-tracking,
|
|
||||||
AC_HELP_STRING([--disable-dependency-tracking],
|
|
||||||
[speeds up one-time build.]),
|
|
||||||
USE_TRACKING=$enableval, USE_TRACKING=yes)
|
|
||||||
AC_MSG_RESULT($USE_TRACKING)
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
dnl -- Enables statically-linked tools
|
dnl -- Enables statically-linked tools
|
||||||
AC_MSG_CHECKING(whether to use static linking)
|
AC_MSG_CHECKING(whether to use static linking)
|
||||||
@@ -593,25 +584,18 @@ case "$CACHE" in
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
if test "$CACHE_CHECK_NEEDS_CHECK" = yes; then
|
if test "$CACHE_CHECK_NEEDS_CHECK" = yes; then
|
||||||
$CACHE_CHECK_CMD -V 2>/dev/null >conftest.tmp
|
CACHE_CHECK_VSN=`"$CACHE_CHECK_CMD" -V 2>/dev/null`
|
||||||
read -r CACHE_CHECK_VSN < conftest.tmp
|
CACHE_CHECK_VSN_MAJOR=`echo "$CACHE_CHECK_VSN" | $AWK -F '.' '{print $1}'`
|
||||||
IFS=.- read -r CACHE_CHECK_VSN_MAJOR CACHE_CHECK_VSN_MINOR CACHE_CHECK_VSN_PATCH LEFTOVER < conftest.tmp
|
CACHE_CHECK_VSN_MINOR=`echo "$CACHE_CHECK_VSN" | $AWK -F '.' '{print $2}'`
|
||||||
rm -f conftest.tmp
|
|
||||||
|
|
||||||
# Require version >= 0.5.4 for --clear-needs-check-flag
|
if test -z "$CACHE_CHECK_VSN_MAJOR" -o -z "$CACHE_CHECK_VSN_MINOR"; then
|
||||||
if test -z "$CACHE_CHECK_VSN_MAJOR" \
|
|
||||||
|| test -z "$CACHE_CHECK_VSN_MINOR" \
|
|
||||||
|| test -z "$CACHE_CHECK_VSN_PATCH"; then
|
|
||||||
AC_MSG_WARN([$CACHE_CHECK_CMD: Bad version "$CACHE_CHECK_VSN" found])
|
AC_MSG_WARN([$CACHE_CHECK_CMD: Bad version "$CACHE_CHECK_VSN" found])
|
||||||
CACHE_CHECK_VERSION_WARN=y
|
CACHE_CHECK_VERSION_WARN=y
|
||||||
CACHE_CHECK_NEEDS_CHECK=no
|
CACHE_CHECK_NEEDS_CHECK=no
|
||||||
elif test "$CACHE_CHECK_VSN_MAJOR" -eq 0 ; then
|
elif test "$CACHE_CHECK_VSN_MAJOR" -eq 0 -a "$CACHE_CHECK_VSN_MINOR" -lt 5; then
|
||||||
if test "$CACHE_CHECK_VSN_MINOR" -lt 5 \
|
AC_MSG_WARN([$CACHE_CHECK_CMD: Old version "$CACHE_CHECK_VSN" found])
|
||||||
|| test "$CACHE_CHECK_VSN_MINOR" -eq 5 -a "$CACHE_CHECK_VSN_PATCH" -lt 4; then
|
CACHE_CHECK_VERSION_WARN=y
|
||||||
AC_MSG_WARN([$CACHE_CHECK_CMD: Old version "$CACHE_CHECK_VSN" found])
|
CACHE_CHECK_NEEDS_CHECK=no
|
||||||
CACHE_CHECK_VERSION_WARN=y
|
|
||||||
CACHE_CHECK_NEEDS_CHECK=no
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
# Empty means a config way to ignore cache dumping
|
# Empty means a config way to ignore cache dumping
|
||||||
@@ -1129,8 +1113,9 @@ AC_ARG_ENABLE(lvmetad,
|
|||||||
AC_HELP_STRING([--enable-lvmetad],
|
AC_HELP_STRING([--enable-lvmetad],
|
||||||
[enable the LVM Metadata Daemon]),
|
[enable the LVM Metadata Daemon]),
|
||||||
LVMETAD=$enableval)
|
LVMETAD=$enableval)
|
||||||
test -n "$LVMETAD" && BUILD_LVMETAD=$LVMETAD
|
AC_MSG_RESULT($LVMETAD)
|
||||||
AC_MSG_RESULT($BUILD_LVMETAD)
|
|
||||||
|
BUILD_LVMETAD=$LVMETAD
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
dnl -- Build lvmpolld
|
dnl -- Build lvmpolld
|
||||||
@@ -1139,12 +1124,11 @@ AC_ARG_ENABLE(lvmpolld,
|
|||||||
AC_HELP_STRING([--enable-lvmpolld],
|
AC_HELP_STRING([--enable-lvmpolld],
|
||||||
[enable the LVM Polling Daemon]),
|
[enable the LVM Polling Daemon]),
|
||||||
LVMPOLLD=$enableval)
|
LVMPOLLD=$enableval)
|
||||||
test -n "$LVMPOLLD" && BUILD_LVMPOLLD=$LVMPOLLD
|
AC_MSG_RESULT($LVMPOLLD)
|
||||||
AC_MSG_RESULT($BUILD_LVMPOLLD)
|
|
||||||
|
BUILD_LVMPOLLD=$LVMPOLLD
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
BUILD_LVMLOCKD=no
|
|
||||||
|
|
||||||
dnl -- Build lockdsanlock
|
dnl -- Build lockdsanlock
|
||||||
AC_MSG_CHECKING(whether to build lockdsanlock)
|
AC_MSG_CHECKING(whether to build lockdsanlock)
|
||||||
AC_ARG_ENABLE(lockd-sanlock,
|
AC_ARG_ENABLE(lockd-sanlock,
|
||||||
@@ -1155,10 +1139,14 @@ AC_MSG_RESULT($LOCKDSANLOCK)
|
|||||||
|
|
||||||
BUILD_LOCKDSANLOCK=$LOCKDSANLOCK
|
BUILD_LOCKDSANLOCK=$LOCKDSANLOCK
|
||||||
|
|
||||||
|
if test "$BUILD_LOCKDSANLOCK" = yes; then
|
||||||
|
AC_DEFINE([LOCKDSANLOCK_SUPPORT], 1, [Define to 1 to include code that uses lvmlockd sanlock option.])
|
||||||
|
fi
|
||||||
|
|
||||||
|
################################################################################
|
||||||
dnl -- Look for sanlock libraries
|
dnl -- Look for sanlock libraries
|
||||||
if test "$BUILD_LOCKDSANLOCK" = yes; then
|
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
|
BUILD_LVMLOCKD=yes
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -1173,23 +1161,26 @@ AC_MSG_RESULT($LOCKDDLM)
|
|||||||
|
|
||||||
BUILD_LOCKDDLM=$LOCKDDLM
|
BUILD_LOCKDDLM=$LOCKDDLM
|
||||||
|
|
||||||
|
if test "$BUILD_LOCKDDLM" = yes; then
|
||||||
|
AC_DEFINE([LOCKDDLM_SUPPORT], 1, [Define to 1 to include code that uses lvmlockd dlm option.])
|
||||||
|
fi
|
||||||
|
|
||||||
|
################################################################################
|
||||||
dnl -- Look for dlm libraries
|
dnl -- Look for dlm libraries
|
||||||
if test "$BUILD_LOCKDDLM" = yes; then
|
if test "$BUILD_LOCKDDLM" = yes; then
|
||||||
PKG_CHECK_MODULES(LOCKD_DLM, libdlm, [HAVE_LOCKD_DLM=yes], $bailout)
|
PKG_CHECK_MODULES(LOCKD_DLM, libdlm, [HAVE_LOCKD_DLM=yes], $bailout)
|
||||||
AC_DEFINE([LOCKDDLM_SUPPORT], 1, [Define to 1 to include code that uses lvmlockd dlm option.])
|
|
||||||
BUILD_LVMLOCKD=yes
|
BUILD_LVMLOCKD=yes
|
||||||
fi
|
fi
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
dnl -- Build lvmlockd
|
dnl -- Build lvmlockd
|
||||||
|
|
||||||
AC_MSG_CHECKING(whether to build lvmlockd)
|
AC_MSG_CHECKING(whether to build lvmlockd)
|
||||||
AC_MSG_RESULT($BUILD_LVMLOCKD)
|
AC_MSG_RESULT($BUILD_LVMLOCKD)
|
||||||
|
|
||||||
if test "$BUILD_LVMLOCKD" = yes; then
|
if test "$BUILD_LVMLOCKD" = yes; then
|
||||||
AS_IF([test "$LVMPOLLD" = no], [AC_MSG_ERROR([cannot build lvmlockd with --disable-lvmpolld.])])
|
AS_IF([test -n "$BUILD_LVMPOLLD"], [BUILD_LVMPOLLD=yes; AC_MSG_WARN([Enabling lvmpolld - required by lvmlockd.])])
|
||||||
AS_IF([test "$LVMETAD" = no], [AC_MSG_ERROR([cannot build lvmlockd with --disable-lvmetad.])])
|
AS_IF([test -n "$BUILD_LVMETAD"], [BUILD_LVMETAD=yes; AC_MSG_WARN([Enabling lvmetad - required by lvmlockd.])])
|
||||||
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.])])
|
|
||||||
AC_MSG_CHECKING([defaults for use_lvmlockd])
|
AC_MSG_CHECKING([defaults for use_lvmlockd])
|
||||||
AC_ARG_ENABLE(use_lvmlockd,
|
AC_ARG_ENABLE(use_lvmlockd,
|
||||||
AC_HELP_STRING([--disable-use-lvmlockd],
|
AC_HELP_STRING([--disable-use-lvmlockd],
|
||||||
@@ -1268,28 +1259,6 @@ fi
|
|||||||
AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMPOLLD, [$DEFAULT_USE_LVMPOLLD],
|
AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMPOLLD, [$DEFAULT_USE_LVMPOLLD],
|
||||||
[Use lvmpolld by default.])
|
[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
|
dnl -- Enable blkid wiping functionality
|
||||||
@@ -1314,7 +1283,7 @@ if test "$BLKID_WIPING" != no; then
|
|||||||
DEFAULT_USE_BLKID_WIPING=1
|
DEFAULT_USE_BLKID_WIPING=1
|
||||||
AC_DEFINE([BLKID_WIPING_SUPPORT], 1, [Define to 1 to use libblkid detection of signatures when wiping.])
|
AC_DEFINE([BLKID_WIPING_SUPPORT], 1, [Define to 1 to use libblkid detection of signatures when wiping.])
|
||||||
else
|
else
|
||||||
DEFAULT_USE_BLKID_WIPING=0
|
DEFAULT_USE_BLKID_WIPING=1
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
DEFAULT_USE_BLKID_WIPING=0
|
DEFAULT_USE_BLKID_WIPING=0
|
||||||
@@ -1357,10 +1326,6 @@ if test "$UDEV_SYNC" = yes; then
|
|||||||
pkg_config_init
|
pkg_config_init
|
||||||
PKG_CHECK_MODULES(UDEV, libudev >= 143, [UDEV_PC="libudev"])
|
PKG_CHECK_MODULES(UDEV, libudev >= 143, [UDEV_PC="libudev"])
|
||||||
AC_DEFINE([UDEV_SYNC_SUPPORT], 1, [Define to 1 to enable synchronisation with udev processing.])
|
AC_DEFINE([UDEV_SYNC_SUPPORT], 1, [Define to 1 to enable synchronisation with udev processing.])
|
||||||
|
|
||||||
AC_CHECK_LIB(udev, udev_device_get_is_initialized, AC_DEFINE([HAVE_LIBUDEV_UDEV_DEVICE_GET_IS_INITIALIZED], 1,
|
|
||||||
[Define to 1 if udev_device_get_is_initialized is available.]))
|
|
||||||
LIBS=$ac_check_lib_save_LIBS
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
dnl -- Enable udev rules
|
dnl -- Enable udev rules
|
||||||
@@ -1460,76 +1425,25 @@ test "$CMDLIB" = yes \
|
|||||||
&& LVM2CMD_LIB=-llvm2cmd \
|
&& LVM2CMD_LIB=-llvm2cmd \
|
||||||
|| LVM2CMD_LIB=
|
|| LVM2CMD_LIB=
|
||||||
|
|
||||||
################################################################################
|
|
||||||
dnl -- Enable D-Bus service
|
|
||||||
AC_MSG_CHECKING(whether to include Python D-Bus support)
|
|
||||||
AC_ARG_ENABLE(dbus-service,
|
|
||||||
AC_HELP_STRING([--enable-dbus-service], [install D-Bus support]),
|
|
||||||
BUILD_LVMDBUSD=$enableval, BUILD_LVMDBUSD=no)
|
|
||||||
AC_MSG_RESULT($BUILD_LVMDBUSD)
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
dnl -- Enable Python liblvm2app bindings
|
dnl -- Enable Python liblvm2app bindings
|
||||||
AC_MSG_CHECKING(whether to build Python wrapper for liblvm2app.so)
|
AC_MSG_CHECKING(whether to build Python wrapper for liblvm2app.so)
|
||||||
AC_ARG_ENABLE(python_bindings,
|
AC_ARG_ENABLE(python_bindings,
|
||||||
AC_HELP_STRING([--enable-python_bindings], [build default Python applib bindings]),
|
AC_HELP_STRING([--enable-python_bindings], [build Python applib bindings]),
|
||||||
PYTHON_BINDINGS=$enableval, PYTHON_BINDINGS=no)
|
PYTHON_BINDINGS=$enableval, PYTHON_BINDINGS=no)
|
||||||
AC_MSG_RESULT($PYTHON_BINDINGS)
|
AC_MSG_RESULT($PYTHON_BINDINGS)
|
||||||
|
|
||||||
AC_MSG_CHECKING(whether to build Python2 wrapper for liblvm2app.so)
|
|
||||||
AC_ARG_ENABLE(python2_bindings,
|
|
||||||
AC_HELP_STRING([--enable-python2_bindings], [build Python2 applib bindings]),
|
|
||||||
PYTHON2_BINDINGS=$enableval, PYTHON2_BINDINGS=no)
|
|
||||||
AC_MSG_RESULT($PYTHON2_BINDINGS)
|
|
||||||
|
|
||||||
|
|
||||||
AC_MSG_CHECKING(whether to build Python3 wrapper for liblvm2app.so)
|
|
||||||
AC_ARG_ENABLE(python3_bindings,
|
|
||||||
AC_HELP_STRING([--enable-python3_bindings], [build Python3 applib bindings]),
|
|
||||||
PYTHON3_BINDINGS=$enableval, PYTHON3_BINDINGS=no)
|
|
||||||
AC_MSG_RESULT($PYTHON3_BINDINGS)
|
|
||||||
|
|
||||||
if test "$PYTHON_BINDINGS" = yes; then
|
if test "$PYTHON_BINDINGS" = yes; then
|
||||||
AC_MSG_ERROR([--enable-python-bindings is replaced by --enable-python2-bindings and --enable-python3-bindings])
|
test "$APPLIB" != yes && AC_MSG_ERROR([--enable-python_bindings requires --enable-applib])
|
||||||
fi
|
|
||||||
|
|
||||||
if test "$PYTHON2_BINDINGS" = yes; then
|
AC_PATH_TOOL(PYTHON, python)
|
||||||
AM_PATH_PYTHON([2])
|
test -z "$PYTHON" && AC_MSG_ERROR([python is required for --enable-python_bindings but cannot be found])
|
||||||
AC_PATH_TOOL(PYTHON2, python2)
|
|
||||||
test -z "$PYTHON2" && AC_MSG_ERROR([python2 is required for --enable-python2_bindings but cannot be found])
|
|
||||||
AC_PATH_TOOL(PYTHON2_CONFIG, python2-config)
|
|
||||||
test -z "$PYTHON2_CONFIG" && AC_PATH_TOOL(PYTHON2_CONFIG, python-config)
|
|
||||||
test -z "$PYTHON2_CONFIG" && AC_MSG_ERROR([python headers are required for --enable-python2_bindings but cannot be found])
|
|
||||||
PYTHON2_INCDIRS=`"$PYTHON2_CONFIG" --includes`
|
|
||||||
PYTHON2_LIBDIRS=`"$PYTHON2_CONFIG" --libs`
|
|
||||||
PYTHON2DIR=$pythondir
|
|
||||||
PYTHON_BINDINGS=yes
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "$PYTHON3_BINDINGS" = yes -o "$BUILD_LVMDBUSD" = yes; then
|
AC_PATH_TOOL(PYTHON_CONFIG, python-config)
|
||||||
unset PYTHON PYTHON_CONFIG
|
test -z "$PYTHON_CONFIG" && AC_MSG_ERROR([python headers are required for --enable-python_bindings but cannot be found])
|
||||||
unset am_cv_pathless_PYTHON ac_cv_path_PYTHON am_cv_python_platform
|
|
||||||
unset am_cv_python_pythondir am_cv_python_version am_cv_python_pyexecdir
|
|
||||||
unset ac_cv_path_PYTHON_CONFIG ac_cv_path_ac_pt_PYTHON_CONFIG
|
|
||||||
AM_PATH_PYTHON([3])
|
|
||||||
PYTHON3=$PYTHON
|
|
||||||
test -z "$PYTHON3" && AC_MSG_ERROR([python3 is required for --enable-python3_bindings or --enable-dbus-service but cannot be found])
|
|
||||||
AC_PATH_TOOL(PYTHON3_CONFIG, python3-config)
|
|
||||||
test -z "$PYTHON3_CONFIG" && AC_MSG_ERROR([python3 headers are required for --enable-python3_bindings or --enable-dbus-service but cannot be found])
|
|
||||||
PYTHON3_INCDIRS=`"$PYTHON3_CONFIG" --includes`
|
|
||||||
PYTHON3_LIBDIRS=`"$PYTHON3_CONFIG" --libs`
|
|
||||||
PYTHON3DIR=$pythondir
|
|
||||||
PYTHON_BINDINGS=yes
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "$BUILD_LVMDBUSD" = yes; then
|
PYTHON_INCDIRS=`"$PYTHON_CONFIG" --includes`
|
||||||
# To get this macro, install autoconf-archive package then run autoreconf
|
PYTHON_LIBDIRS=`"$PYTHON_CONFIG" --libs`
|
||||||
AC_PYTHON_MODULE([pyudev], [Required], python3)
|
|
||||||
AC_PYTHON_MODULE([dbus], [Required], python3)
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "$PYTHON_BINDINGS" = yes -o "$PYTHON2_BINDINGS" = yes -o "$PYTHON3_BINDINGS" = yes; then
|
|
||||||
test "$APPLIB" != yes && AC_MSG_ERROR([Python_bindings require --enable-applib])
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
@@ -1616,10 +1530,6 @@ if [[ \( "$LVM1" = shared -o "$POOL" = shared -o "$CLUSTER" = shared \
|
|||||||
AC_MSG_ERROR([Features cannot be 'shared' when building statically])
|
AC_MSG_ERROR([Features cannot be 'shared' when building statically])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
################################################################################
|
|
||||||
AC_CHECK_LIB(m, log10,
|
|
||||||
[M_LIBS="-lm"], hard_bailout)
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
AC_CHECK_LIB([pthread], [pthread_mutex_lock],
|
AC_CHECK_LIB([pthread], [pthread_mutex_lock],
|
||||||
[PTHREAD_LIBS="-lpthread"], hard_bailout)
|
[PTHREAD_LIBS="-lpthread"], hard_bailout)
|
||||||
@@ -1660,10 +1570,11 @@ if test "$REALTIME" = yes; then
|
|||||||
if test "$HAVE_REALTIME" = yes; then
|
if test "$HAVE_REALTIME" = yes; then
|
||||||
AC_DEFINE([HAVE_REALTIME], 1, [Define to 1 to include support for realtime clock.])
|
AC_DEFINE([HAVE_REALTIME], 1, [Define to 1 to include support for realtime clock.])
|
||||||
LIBS="-lrt $LIBS"
|
LIBS="-lrt $LIBS"
|
||||||
RT_LIB="-lrt"
|
RT_PC="librt"
|
||||||
else
|
else
|
||||||
AC_MSG_WARN(Disabling realtime clock)
|
AC_MSG_WARN(Disabling realtime clock)
|
||||||
fi
|
fi
|
||||||
|
AC_MSG_RESULT($HAVE_REALTIME)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
dnl Check if the system has struct stat st_ctim.
|
dnl Check if the system has struct stat st_ctim.
|
||||||
@@ -1866,10 +1777,12 @@ test "$lvm_exec_prefix" = NONE && lvm_exec_prefix=$ac_default_prefix
|
|||||||
LVM_PATH="$lvm_exec_prefix/sbin/lvm"
|
LVM_PATH="$lvm_exec_prefix/sbin/lvm"
|
||||||
AC_DEFINE_UNQUOTED(LVM_PATH, ["$LVM_PATH"], [Path to lvm binary.])
|
AC_DEFINE_UNQUOTED(LVM_PATH, ["$LVM_PATH"], [Path to lvm binary.])
|
||||||
|
|
||||||
clvmd_prefix=$ac_default_prefix
|
if test "$CLVMD" != none; then
|
||||||
test "$prefix" != NONE && clvmd_prefix=$prefix
|
clvmd_prefix=$ac_default_prefix
|
||||||
CLVMD_PATH="$clvmd_prefix/sbin/clvmd"
|
test "$prefix" != NONE && clvmd_prefix=$prefix
|
||||||
AC_DEFINE_UNQUOTED(CLVMD_PATH, ["$CLVMD_PATH"], [Path to clvmd binary.])
|
CLVMD_PATH="$clvmd_prefix/sbin/clvmd"
|
||||||
|
AC_DEFINE_UNQUOTED(CLVMD_PATH, ["$CLVMD_PATH"], [Path to clvmd binary.])
|
||||||
|
fi
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
dnl -- dmeventd pidfile and executable path
|
dnl -- dmeventd pidfile and executable path
|
||||||
@@ -1933,12 +1846,8 @@ AC_DEFINE_UNQUOTED(DEFAULT_CACHE_SUBDIR, ["$DEFAULT_CACHE_SUBDIR"],
|
|||||||
|
|
||||||
AC_ARG_WITH(default-locking-dir,
|
AC_ARG_WITH(default-locking-dir,
|
||||||
AC_HELP_STRING([--with-default-locking-dir=DIR],
|
AC_HELP_STRING([--with-default-locking-dir=DIR],
|
||||||
[default locking directory [autodetect_lock_dir/lvm]]),
|
[default locking directory [/var/lock/lvm]]),
|
||||||
DEFAULT_LOCK_DIR=$withval,
|
DEFAULT_LOCK_DIR=$withval, DEFAULT_LOCK_DIR="/var/lock/lvm")
|
||||||
[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)])
|
|
||||||
AC_DEFINE_UNQUOTED(DEFAULT_LOCK_DIR, ["$DEFAULT_LOCK_DIR"],
|
AC_DEFINE_UNQUOTED(DEFAULT_LOCK_DIR, ["$DEFAULT_LOCK_DIR"],
|
||||||
[Name of default locking directory.])
|
[Name of default locking directory.])
|
||||||
|
|
||||||
@@ -1962,14 +1871,14 @@ test "$interface" != ioctl && AC_MSG_ERROR([--with-interface=ioctl required. fs
|
|||||||
AC_MSG_RESULT($interface)
|
AC_MSG_RESULT($interface)
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
read DM_LIB_VERSION < "$srcdir"/VERSION_DM 2>/dev/null || DM_LIB_VERSION=Unknown
|
DM_LIB_VERSION="\"`cat "$srcdir"/VERSION_DM 2>/dev/null || echo Unknown`\""
|
||||||
AC_DEFINE_UNQUOTED(DM_LIB_VERSION, "$DM_LIB_VERSION", [Library version])
|
AC_DEFINE_UNQUOTED(DM_LIB_VERSION, $DM_LIB_VERSION, [Library version])
|
||||||
|
|
||||||
DM_LIB_PATCHLEVEL=`cat "$srcdir"/VERSION_DM | $AWK -F '[[-. ]]' '{printf "%s.%s.%s",$1,$2,$3}'`
|
DM_LIB_PATCHLEVEL=`cat "$srcdir"/VERSION_DM | $AWK -F '[[-. ]]' '{printf "%s.%s.%s",$1,$2,$3}'`
|
||||||
|
|
||||||
read VER < "$srcdir"/VERSION 2>/dev/null || VER=Unknown
|
LVM_VERSION="\"`cat "$srcdir"/VERSION 2>/dev/null || echo Unknown`\""
|
||||||
|
|
||||||
LVM_VERSION=\"$VER\"
|
VER=`cat "$srcdir"/VERSION`
|
||||||
LVM_RELEASE_DATE="\"`echo $VER | $SED 's/.* (//;s/).*//'`\""
|
LVM_RELEASE_DATE="\"`echo $VER | $SED 's/.* (//;s/).*//'`\""
|
||||||
VER=`echo "$VER" | $AWK '{print $1}'`
|
VER=`echo "$VER" | $AWK '{print $1}'`
|
||||||
LVM_RELEASE="\"`echo "$VER" | $AWK -F '-' '{print $2}'`\""
|
LVM_RELEASE="\"`echo "$VER" | $AWK -F '-' '{print $2}'`\""
|
||||||
@@ -1985,17 +1894,14 @@ AC_SUBST(AWK)
|
|||||||
AC_SUBST(BLKID_PC)
|
AC_SUBST(BLKID_PC)
|
||||||
AC_SUBST(BUILD_CMIRRORD)
|
AC_SUBST(BUILD_CMIRRORD)
|
||||||
AC_SUBST(BUILD_DMEVENTD)
|
AC_SUBST(BUILD_DMEVENTD)
|
||||||
AC_SUBST(BUILD_LVMDBUSD)
|
|
||||||
AC_SUBST(BUILD_LVMETAD)
|
AC_SUBST(BUILD_LVMETAD)
|
||||||
AC_SUBST(BUILD_LVMPOLLD)
|
AC_SUBST(BUILD_LVMPOLLD)
|
||||||
AC_SUBST(BUILD_LVMLOCKD)
|
AC_SUBST(BUILD_LVMLOCKD)
|
||||||
AC_SUBST(BUILD_LOCKDSANLOCK)
|
AC_SUBST(BUILD_LOCKDSANLOCK)
|
||||||
AC_SUBST(BUILD_LOCKDDLM)
|
AC_SUBST(BUILD_LOCKDDLM)
|
||||||
AC_SUBST(BUILD_NOTIFYDBUS)
|
|
||||||
AC_SUBST(CACHE)
|
AC_SUBST(CACHE)
|
||||||
AC_SUBST(CFLAGS)
|
AC_SUBST(CFLAGS)
|
||||||
AC_SUBST(CFLOW_CMD)
|
AC_SUBST(CFLOW_CMD)
|
||||||
AC_SUBST(CHMOD)
|
|
||||||
AC_SUBST(CLDFLAGS)
|
AC_SUBST(CLDFLAGS)
|
||||||
AC_SUBST(CLDNOWHOLEARCHIVE)
|
AC_SUBST(CLDNOWHOLEARCHIVE)
|
||||||
AC_SUBST(CLDWHOLEARCHIVE)
|
AC_SUBST(CLDWHOLEARCHIVE)
|
||||||
@@ -2040,6 +1946,7 @@ AC_SUBST(DLM_LIBS)
|
|||||||
AC_SUBST(DL_LIBS)
|
AC_SUBST(DL_LIBS)
|
||||||
AC_SUBST(DMEVENTD)
|
AC_SUBST(DMEVENTD)
|
||||||
AC_SUBST(DMEVENTD_PATH)
|
AC_SUBST(DMEVENTD_PATH)
|
||||||
|
AC_SUBST(DM_LIB_VERSION)
|
||||||
AC_SUBST(DM_LIB_PATCHLEVEL)
|
AC_SUBST(DM_LIB_PATCHLEVEL)
|
||||||
AC_SUBST(ELDFLAGS)
|
AC_SUBST(ELDFLAGS)
|
||||||
AC_SUBST(FSADM)
|
AC_SUBST(FSADM)
|
||||||
@@ -2070,23 +1977,15 @@ AC_SUBST(OCF)
|
|||||||
AC_SUBST(OCFDIR)
|
AC_SUBST(OCFDIR)
|
||||||
AC_SUBST(PKGCONFIG)
|
AC_SUBST(PKGCONFIG)
|
||||||
AC_SUBST(POOL)
|
AC_SUBST(POOL)
|
||||||
AC_SUBST(M_LIBS)
|
|
||||||
AC_SUBST(PTHREAD_LIBS)
|
AC_SUBST(PTHREAD_LIBS)
|
||||||
AC_SUBST(PYTHON2)
|
AC_SUBST(PYTHON)
|
||||||
AC_SUBST(PYTHON3)
|
|
||||||
AC_SUBST(PYTHON_BINDINGS)
|
AC_SUBST(PYTHON_BINDINGS)
|
||||||
AC_SUBST(PYTHON2_BINDINGS)
|
AC_SUBST(PYTHON_INCDIRS)
|
||||||
AC_SUBST(PYTHON3_BINDINGS)
|
AC_SUBST(PYTHON_LIBDIRS)
|
||||||
AC_SUBST(PYTHON2_INCDIRS)
|
|
||||||
AC_SUBST(PYTHON3_INCDIRS)
|
|
||||||
AC_SUBST(PYTHON2_LIBDIRS)
|
|
||||||
AC_SUBST(PYTHON3_LIBDIRS)
|
|
||||||
AC_SUBST(PYTHON2DIR)
|
|
||||||
AC_SUBST(PYTHON3DIR)
|
|
||||||
AC_SUBST(QUORUM_CFLAGS)
|
AC_SUBST(QUORUM_CFLAGS)
|
||||||
AC_SUBST(QUORUM_LIBS)
|
AC_SUBST(QUORUM_LIBS)
|
||||||
AC_SUBST(RAID)
|
AC_SUBST(RAID)
|
||||||
AC_SUBST(RT_LIB)
|
AC_SUBST(RT_PC)
|
||||||
AC_SUBST(READLINE_LIBS)
|
AC_SUBST(READLINE_LIBS)
|
||||||
AC_SUBST(REPLICATORS)
|
AC_SUBST(REPLICATORS)
|
||||||
AC_SUBST(SACKPT_CFLAGS)
|
AC_SUBST(SACKPT_CFLAGS)
|
||||||
@@ -2115,7 +2014,6 @@ AC_SUBST(UDEV_SYNC)
|
|||||||
AC_SUBST(UDEV_SYSTEMD_BACKGROUND_JOBS)
|
AC_SUBST(UDEV_SYSTEMD_BACKGROUND_JOBS)
|
||||||
AC_SUBST(UDEV_RULE_EXEC_DETECTION)
|
AC_SUBST(UDEV_RULE_EXEC_DETECTION)
|
||||||
AC_SUBST(UDEV_HAS_BUILTIN_BLKID)
|
AC_SUBST(UDEV_HAS_BUILTIN_BLKID)
|
||||||
AC_SUBST(USE_TRACKING)
|
|
||||||
AC_SUBST(VALGRIND_POOL)
|
AC_SUBST(VALGRIND_POOL)
|
||||||
AC_SUBST(WRITE_INSTALL)
|
AC_SUBST(WRITE_INSTALL)
|
||||||
AC_SUBST(DMEVENTD_PIDFILE)
|
AC_SUBST(DMEVENTD_PIDFILE)
|
||||||
@@ -2154,8 +2052,6 @@ daemons/dmeventd/plugins/raid/Makefile
|
|||||||
daemons/dmeventd/plugins/mirror/Makefile
|
daemons/dmeventd/plugins/mirror/Makefile
|
||||||
daemons/dmeventd/plugins/snapshot/Makefile
|
daemons/dmeventd/plugins/snapshot/Makefile
|
||||||
daemons/dmeventd/plugins/thin/Makefile
|
daemons/dmeventd/plugins/thin/Makefile
|
||||||
daemons/lvmdbusd/Makefile
|
|
||||||
daemons/lvmdbusd/path.py
|
|
||||||
daemons/lvmetad/Makefile
|
daemons/lvmetad/Makefile
|
||||||
daemons/lvmpolld/Makefile
|
daemons/lvmpolld/Makefile
|
||||||
daemons/lvmlockd/Makefile
|
daemons/lvmlockd/Makefile
|
||||||
@@ -2172,7 +2068,7 @@ lib/format_pool/Makefile
|
|||||||
lib/locking/Makefile
|
lib/locking/Makefile
|
||||||
lib/mirror/Makefile
|
lib/mirror/Makefile
|
||||||
lib/replicator/Makefile
|
lib/replicator/Makefile
|
||||||
include/lvm-version.h
|
lib/misc/lvm-version.h
|
||||||
lib/raid/Makefile
|
lib/raid/Makefile
|
||||||
lib/snapshot/Makefile
|
lib/snapshot/Makefile
|
||||||
lib/thin/Makefile
|
lib/thin/Makefile
|
||||||
@@ -2193,14 +2089,12 @@ scripts/blk_availability_init_red_hat
|
|||||||
scripts/blk_availability_systemd_red_hat.service
|
scripts/blk_availability_systemd_red_hat.service
|
||||||
scripts/clvmd_init_red_hat
|
scripts/clvmd_init_red_hat
|
||||||
scripts/cmirrord_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.service
|
||||||
scripts/dm_event_systemd_red_hat.socket
|
scripts/dm_event_systemd_red_hat.socket
|
||||||
scripts/lvm2_cluster_activation_red_hat.sh
|
scripts/lvm2_cluster_activation_red_hat.sh
|
||||||
scripts/lvm2_cluster_activation_systemd_red_hat.service
|
scripts/lvm2_cluster_activation_systemd_red_hat.service
|
||||||
scripts/lvm2_clvmd_systemd_red_hat.service
|
scripts/lvm2_clvmd_systemd_red_hat.service
|
||||||
scripts/lvm2_cmirrord_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_init_red_hat
|
||||||
scripts/lvm2_lvmetad_systemd_red_hat.service
|
scripts/lvm2_lvmetad_systemd_red_hat.service
|
||||||
scripts/lvm2_lvmetad_systemd_red_hat.socket
|
scripts/lvm2_lvmetad_systemd_red_hat.socket
|
||||||
|
|||||||
@@ -1,122 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2015 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 General Public License v.2.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Coverity usage:
|
|
||||||
*
|
|
||||||
* translate model into xml
|
|
||||||
* cov-make-library -of coverity_model.xml coverity_model.c
|
|
||||||
*
|
|
||||||
* compile (using outdir 'cov'):
|
|
||||||
* cov-build --dir=cov make CC=gcc
|
|
||||||
*
|
|
||||||
* analyze (agressively, using 'cov')
|
|
||||||
* cov-analyze --dir cov --wait-for-license --hfa --concurrency --enable-fnptr --enable-constraint-fpp --security --all --aggressiveness-level=high --field-offset-escape --user-model-file=coverity/coverity_model.xml
|
|
||||||
*
|
|
||||||
* generate html output (to 'html' from 'cov'):
|
|
||||||
* cov-format-errors --dir cov --html-output html
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct lv_segment;
|
|
||||||
struct logical_volume;
|
|
||||||
|
|
||||||
struct lv_segment *first_seg(const struct logical_volume *lv)
|
|
||||||
{
|
|
||||||
return ((struct lv_segment **)lv)[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
struct lv_segment *last_seg(const struct logical_volume *lv)
|
|
||||||
{
|
|
||||||
return ((struct lv_segment **)lv)[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* simple_memccpy() from glibc */
|
|
||||||
void *memccpy(void *dest, const void *src, int c, size_t n)
|
|
||||||
{
|
|
||||||
const char *s = src;
|
|
||||||
char *d = dest;
|
|
||||||
|
|
||||||
while (n-- > 0)
|
|
||||||
if ((*d++ = *s++) == (char) c)
|
|
||||||
return d;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 2 lines bellow needs to be placed in coverity/config/user_nodefs.h
|
|
||||||
* Not sure about any other way.
|
|
||||||
* Without them, coverity shows warning since x86 system header files
|
|
||||||
* are using inline assembly to reset fdset
|
|
||||||
*/
|
|
||||||
//#nodef FD_ZERO model_FD_ZERO
|
|
||||||
//void model_FD_ZERO(void *fdset);
|
|
||||||
|
|
||||||
void model_FD_ZERO(void *fdset)
|
|
||||||
{
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
for (i = 0; i < 1024 / 8 / sizeof(long); ++i)
|
|
||||||
((long*)fdset)[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Added extra pointer check to not need these models,
|
|
||||||
* for now just keep then in file
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
struct cmd_context;
|
|
||||||
struct profile;
|
|
||||||
|
|
||||||
const char *find_config_tree_str(struct cmd_context *cmd, int id, struct profile *profile)
|
|
||||||
{
|
|
||||||
return "text";
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *find_config_tree_str_allow_empty(struct cmd_context *cmd, int id, struct profile *profile)
|
|
||||||
{
|
|
||||||
return "text";
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Until fixed coverity case# 00531860:
|
|
||||||
* A FORWARD_NULL false positive on a recursive function call
|
|
||||||
*
|
|
||||||
* model also these functions:
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
const struct dm_config_node;
|
|
||||||
const struct dm_config_node *find_config_tree_array(struct cmd_context *cmd, int id, struct profile *profile)
|
|
||||||
{
|
|
||||||
const struct dm_config_node *cn;
|
|
||||||
|
|
||||||
return cn;
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct dm_config_node *find_config_tree_node(struct cmd_context *cmd, int id, struct profile *profile)
|
|
||||||
{
|
|
||||||
const struct dm_config_node *cn;
|
|
||||||
|
|
||||||
return cn;
|
|
||||||
}
|
|
||||||
|
|
||||||
int find_config_tree_bool(struct cmd_context *cmd, int id, struct profile *profile)
|
|
||||||
{
|
|
||||||
int b;
|
|
||||||
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program; if not, write to the Free Software Foundation,
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
srcdir = @srcdir@
|
srcdir = @srcdir@
|
||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
@@ -44,12 +44,8 @@ ifeq ("@BUILD_LVMLOCKD@", "yes")
|
|||||||
SUBDIRS += lvmlockd
|
SUBDIRS += lvmlockd
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ("@BUILD_LVMDBUSD@", "yes")
|
|
||||||
SUBDIRS += lvmdbusd
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(MAKECMDGOALS),distclean)
|
ifeq ($(MAKECMDGOALS),distclean)
|
||||||
SUBDIRS = clvmd cmirrord dmeventd lvmetad lvmpolld lvmlockd lvmdbusd
|
SUBDIRS = clvmd cmirrord dmeventd lvmetad lvmpolld lvmlockd
|
||||||
endif
|
endif
|
||||||
|
|
||||||
include $(top_builddir)/make.tmpl
|
include $(top_builddir)/make.tmpl
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program; if not, write to the Free Software Foundation,
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
srcdir = @srcdir@
|
srcdir = @srcdir@
|
||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Definitions for CLVMD server and clients */
|
/* Definitions for CLVMD server and clients */
|
||||||
@@ -50,7 +50,7 @@ struct clvm_header {
|
|||||||
#define CLVMD_FLAG_REMOTE 8 /* Do this on all nodes except for the local node */
|
#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 */
|
/* 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 */
|
/* Internal commands & replies */
|
||||||
#define CLVMD_CMD_REPLY 1
|
#define CLVMD_CMD_REPLY 1
|
||||||
@@ -76,10 +76,8 @@ struct clvm_header {
|
|||||||
#define CLVMD_CMD_SYNC_NAMES 45
|
#define CLVMD_CMD_SYNC_NAMES 45
|
||||||
|
|
||||||
/* Used internally by some callers, but not part of the protocol.*/
|
/* Used internally by some callers, but not part of the protocol.*/
|
||||||
#ifndef NODE_ALL
|
#define NODE_ALL "*"
|
||||||
# define NODE_ALL "*"
|
#define NODE_LOCAL "."
|
||||||
# define NODE_LOCAL "."
|
#define NODE_REMOTE "^"
|
||||||
# define NODE_REMOTE "^"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* 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,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* 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,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* 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,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* 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,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "clvmd-common.h"
|
#include "clvmd-common.h"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -154,7 +154,7 @@ static void usage(const char *prog, FILE *file)
|
|||||||
{
|
{
|
||||||
fprintf(file, "Usage: %s [options]\n"
|
fprintf(file, "Usage: %s [options]\n"
|
||||||
" -C Sets debug level (from -d) on all clvmd instances clusterwide\n"
|
" -C Sets debug level (from -d) on all clvmd instances clusterwide\n"
|
||||||
" -d[<n>] Set debug logging (0:none, 1:stderr (implies -f option), 2:syslog)\n"
|
" -d[n] Set debug logging (0:none, 1:stderr (implies -f option), 2:syslog)\n"
|
||||||
" -E<uuid> Take this lock uuid as exclusively locked resource (for restart)\n"
|
" -E<uuid> Take this lock uuid as exclusively locked resource (for restart)\n"
|
||||||
" -f Don't fork, run in the foreground\n"
|
" -f Don't fork, run in the foreground\n"
|
||||||
" -h Show this help information\n"
|
" -h Show this help information\n"
|
||||||
@@ -374,7 +374,7 @@ int main(int argc, char *argv[])
|
|||||||
/* Deal with command-line arguments */
|
/* Deal with command-line arguments */
|
||||||
opterr = 0;
|
opterr = 0;
|
||||||
optind = 0;
|
optind = 0;
|
||||||
while ((opt = getopt_long(argc, argv, "Vhfd:t:RST:CI:E:",
|
while ((opt = getopt_long(argc, argv, "vVhfd:t:RST:CI:E:",
|
||||||
longopts, NULL)) != -1) {
|
longopts, NULL)) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'h':
|
case 'h':
|
||||||
@@ -604,10 +604,7 @@ int main(int argc, char *argv[])
|
|||||||
local_client_head.fd, &local_client_head, newfd->fd, newfd);
|
local_client_head.fd, &local_client_head, newfd->fd, newfd);
|
||||||
|
|
||||||
/* Don't let anyone else to do work until we are started */
|
/* Don't let anyone else to do work until we are started */
|
||||||
if (pthread_create(&lvm_thread, &stack_attr, lvm_thread_fn, &lvm_params)) {
|
pthread_create(&lvm_thread, &stack_attr, lvm_thread_fn, &lvm_params);
|
||||||
log_sys_error("pthread_create", "");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Don't start until the LVM thread is ready */
|
/* Don't start until the LVM thread is ready */
|
||||||
pthread_barrier_wait(&lvm_start_barrier);
|
pthread_barrier_wait(&lvm_start_barrier);
|
||||||
@@ -858,12 +855,12 @@ static void main_loop(int cmd_timeout)
|
|||||||
int quorate = clops->is_quorate();
|
int quorate = clops->is_quorate();
|
||||||
int client_count = 0;
|
int client_count = 0;
|
||||||
int max_fd = 0;
|
int max_fd = 0;
|
||||||
struct local_client *lastfd = &local_client_head;
|
|
||||||
struct local_client *nextfd = local_client_head.next;
|
|
||||||
|
|
||||||
/* Wait on the cluster FD and all local sockets/pipes */
|
/* Wait on the cluster FD and all local sockets/pipes */
|
||||||
local_client_head.fd = clops->get_main_cluster_fd();
|
local_client_head.fd = clops->get_main_cluster_fd();
|
||||||
FD_ZERO(&in);
|
FD_ZERO(&in);
|
||||||
|
struct local_client *lastfd = &local_client_head;
|
||||||
|
struct local_client *nextfd = local_client_head.next;
|
||||||
|
|
||||||
for (thisfd = &local_client_head; thisfd; thisfd = thisfd->next) {
|
for (thisfd = &local_client_head; thisfd; thisfd = thisfd->next) {
|
||||||
client_count++;
|
client_count++;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _CLVMD_H
|
#ifndef _CLVMD_H
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "clvmd-common.h"
|
#include "clvmd-common.h"
|
||||||
@@ -291,7 +291,6 @@ static int hold_lock(char *resource, int mode, int flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
lvi->lock_mode = mode;
|
lvi->lock_mode = mode;
|
||||||
lvi->lock_id = 0;
|
|
||||||
status = sync_lock(resource, mode, flags & ~LCKF_CONVERT, &lvi->lock_id);
|
status = sync_lock(resource, mode, flags & ~LCKF_CONVERT, &lvi->lock_id);
|
||||||
saved_errno = errno;
|
saved_errno = errno;
|
||||||
if (status) {
|
if (status) {
|
||||||
@@ -663,8 +662,7 @@ int do_refresh_cache(void)
|
|||||||
|
|
||||||
init_full_scan_done(0);
|
init_full_scan_done(0);
|
||||||
init_ignore_suspended_devices(1);
|
init_ignore_suspended_devices(1);
|
||||||
lvmcache_force_next_label_scan();
|
lvmcache_label_scan(cmd, 2);
|
||||||
lvmcache_label_scan(cmd);
|
|
||||||
dm_pool_empty(cmd->mem);
|
dm_pool_empty(cmd->mem);
|
||||||
|
|
||||||
pthread_mutex_unlock(&lvm_lock);
|
pthread_mutex_unlock(&lvm_lock);
|
||||||
@@ -901,12 +899,8 @@ int init_clvm(struct dm_hash_table *excl_uuid)
|
|||||||
if (!get_initial_state(excl_uuid))
|
if (!get_initial_state(excl_uuid))
|
||||||
log_error("Cannot load initial lock states.");
|
log_error("Cannot load initial lock states.");
|
||||||
|
|
||||||
if (!udev_init_library_context())
|
|
||||||
stack;
|
|
||||||
|
|
||||||
if (!(cmd = create_toolcontext(1, NULL, 0, 1, 1, 1))) {
|
if (!(cmd = create_toolcontext(1, NULL, 0, 1, 1, 1))) {
|
||||||
log_error("Failed to allocate command context");
|
log_error("Failed to allocate command context");
|
||||||
udev_fin_library_context();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -933,7 +927,6 @@ void destroy_lvm(void)
|
|||||||
if (cmd) {
|
if (cmd) {
|
||||||
memlock_dec_daemon(cmd);
|
memlock_dec_daemon(cmd);
|
||||||
destroy_toolcontext(cmd);
|
destroy_toolcontext(cmd);
|
||||||
udev_fin_library_context();
|
|
||||||
cmd = NULL;
|
cmd = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Functions in lvm-functions.c */
|
/* Functions in lvm-functions.c */
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* FIXME Remove duplicated functions from this file. */
|
/* FIXME Remove duplicated functions from this file. */
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program; if not, write to the Free Software Foundation,
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
srcdir = @srcdir@
|
srcdir = @srcdir@
|
||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
@@ -15,7 +15,6 @@
|
|||||||
#include "link_mon.h"
|
#include "link_mon.h"
|
||||||
#include "local.h"
|
#include "local.h"
|
||||||
|
|
||||||
#include <getopt.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
@@ -33,49 +32,14 @@ static void daemonize(void);
|
|||||||
static void init_all(void);
|
static void init_all(void);
|
||||||
static void cleanup_all(void);
|
static void cleanup_all(void);
|
||||||
|
|
||||||
static void usage (FILE *dest)
|
int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused)))
|
||||||
{
|
{
|
||||||
fprintf (dest, "Usage: cmirrord [options]\n"
|
daemonize();
|
||||||
" -f, --foreground stay in the foreground, log to the terminal\n"
|
|
||||||
" -h, --help print this help\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
int foreground_mode = 0;
|
|
||||||
struct option longopts[] = {
|
|
||||||
{ "foreground", no_argument, NULL, 'f' },
|
|
||||||
{ "help" , no_argument, NULL, 'h' },
|
|
||||||
{ 0, 0, 0, 0 }
|
|
||||||
};
|
|
||||||
int opt;
|
|
||||||
|
|
||||||
while ((opt = getopt_long (argc, argv, "fh", longopts, NULL)) != -1) {
|
|
||||||
switch (opt) {
|
|
||||||
case 'f':
|
|
||||||
foreground_mode = 1;
|
|
||||||
break;
|
|
||||||
case 'h':
|
|
||||||
usage (stdout);
|
|
||||||
exit (0);
|
|
||||||
default:
|
|
||||||
usage (stderr);
|
|
||||||
exit (2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (optind < argc) {
|
|
||||||
usage (stderr);
|
|
||||||
exit (2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!foreground_mode)
|
|
||||||
daemonize();
|
|
||||||
|
|
||||||
init_all();
|
init_all();
|
||||||
|
|
||||||
/* Parent can now exit, we're ready to handle requests */
|
/* Parent can now exit, we're ready to handle requests */
|
||||||
if (!foreground_mode)
|
kill(getppid(), SIGTERM);
|
||||||
kill(getppid(), SIGTERM);
|
|
||||||
|
|
||||||
LOG_PRINT("Starting cmirrord:");
|
LOG_PRINT("Starting cmirrord:");
|
||||||
LOG_PRINT(" Built: "__DATE__" "__TIME__"\n");
|
LOG_PRINT(" Built: "__DATE__" "__TIME__"\n");
|
||||||
@@ -245,16 +209,6 @@ static void daemonize(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
LOG_OPEN("cmirrord", LOG_PID, LOG_DAEMON);
|
LOG_OPEN("cmirrord", LOG_PID, LOG_DAEMON);
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* init_all
|
|
||||||
*
|
|
||||||
* Initialize modules. Exit on failure.
|
|
||||||
*/
|
|
||||||
static void init_all(void)
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
|
|
||||||
(void) dm_prepare_selinux_context(CMIRRORD_PIDFILE, S_IFREG);
|
(void) dm_prepare_selinux_context(CMIRRORD_PIDFILE, S_IFREG);
|
||||||
if (dm_create_lockfile(CMIRRORD_PIDFILE) == 0)
|
if (dm_create_lockfile(CMIRRORD_PIDFILE) == 0)
|
||||||
@@ -273,6 +227,16 @@ static void init_all(void)
|
|||||||
signal(SIGUSR2, &sig_handler);
|
signal(SIGUSR2, &sig_handler);
|
||||||
sigemptyset(&signal_mask);
|
sigemptyset(&signal_mask);
|
||||||
signal_received = 0;
|
signal_received = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* init_all
|
||||||
|
*
|
||||||
|
* Initialize modules. Exit on failure.
|
||||||
|
*/
|
||||||
|
static void init_all(void)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
if ((r = init_local()) ||
|
if ((r = init_local()) ||
|
||||||
(r = init_cluster())) {
|
(r = init_cluster())) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* 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,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "cluster.h"
|
#include "cluster.h"
|
||||||
@@ -104,11 +104,10 @@ static SaVersionT version = { 'B', 1, 1 };
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DEBUGGING_HISTORY 100
|
#define DEBUGGING_HISTORY 100
|
||||||
#define DEBUGGING_BUFLEN 128
|
|
||||||
#define LOG_SPRINT(cc, f, arg...) do { \
|
#define LOG_SPRINT(cc, f, arg...) do { \
|
||||||
cc->idx++; \
|
cc->idx++; \
|
||||||
cc->idx = cc->idx % DEBUGGING_HISTORY; \
|
cc->idx = cc->idx % DEBUGGING_HISTORY; \
|
||||||
snprintf(cc->debugging[cc->idx], DEBUGGING_BUFLEN, f, ## arg); \
|
sprintf(cc->debugging[cc->idx], f, ## arg); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static int log_resp_rec = 0;
|
static int log_resp_rec = 0;
|
||||||
@@ -151,7 +150,7 @@ struct clog_cpg {
|
|||||||
uint32_t checkpoint_requesters[MAX_CHECKPOINT_REQUESTERS];
|
uint32_t checkpoint_requesters[MAX_CHECKPOINT_REQUESTERS];
|
||||||
struct checkpoint_data *checkpoint_list;
|
struct checkpoint_data *checkpoint_list;
|
||||||
int idx;
|
int idx;
|
||||||
char debugging[DEBUGGING_HISTORY][DEBUGGING_BUFLEN];
|
char debugging[DEBUGGING_HISTORY][128];
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct dm_list clog_cpg_list;
|
static struct dm_list clog_cpg_list;
|
||||||
@@ -1295,9 +1294,7 @@ static void cpg_join_callback(struct clog_cpg *match,
|
|||||||
uint32_t my_pid = (uint32_t)getpid();
|
uint32_t my_pid = (uint32_t)getpid();
|
||||||
uint32_t lowest = match->lowest_id;
|
uint32_t lowest = match->lowest_id;
|
||||||
struct clog_request *rq;
|
struct clog_request *rq;
|
||||||
char dbuf[64] = { 0 };
|
char dbuf[32] = { 0 };
|
||||||
char *dbuf_p = dbuf;
|
|
||||||
size_t dbuf_rem = sizeof dbuf;
|
|
||||||
|
|
||||||
/* Assign my_cluster_id */
|
/* Assign my_cluster_id */
|
||||||
if ((my_cluster_id == 0xDEAD) && (joined->pid == my_pid))
|
if ((my_cluster_id == 0xDEAD) && (joined->pid == my_pid))
|
||||||
@@ -1313,17 +1310,9 @@ static void cpg_join_callback(struct clog_cpg *match,
|
|||||||
if (joined->nodeid == my_cluster_id)
|
if (joined->nodeid == my_cluster_id)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
for (i = 0; i < member_list_entries - 1; i++) {
|
for (i = 0; i < member_list_entries - 1; i++)
|
||||||
int written = snprintf(dbuf_p, dbuf_rem, "%u-", member_list[i].nodeid);
|
sprintf(dbuf+strlen(dbuf), "%u-", member_list[i].nodeid);
|
||||||
if (written < 0) continue; /* impossible */
|
sprintf(dbuf+strlen(dbuf), "(%u)", joined->nodeid);
|
||||||
if ((unsigned)written >= dbuf_rem) {
|
|
||||||
dbuf_rem = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
dbuf_rem -= written;
|
|
||||||
dbuf_p += written;
|
|
||||||
}
|
|
||||||
snprintf(dbuf_p, dbuf_rem, "(%u)", joined->nodeid);
|
|
||||||
LOG_COND(log_checkpoint, "[%s] Joining node, %u needs checkpoint [%s]",
|
LOG_COND(log_checkpoint, "[%s] Joining node, %u needs checkpoint [%s]",
|
||||||
SHORT_UUID(match->name.value), joined->nodeid, dbuf);
|
SHORT_UUID(match->name.value), joined->nodeid, dbuf);
|
||||||
|
|
||||||
@@ -1440,7 +1429,7 @@ static void cpg_leave_callback(struct clog_cpg *match,
|
|||||||
free(rq);
|
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];
|
match->checkpoint_requesters[j] = match->checkpoint_requesters[i];
|
||||||
if (match->checkpoint_requesters[i] == left->nodeid) {
|
if (match->checkpoint_requesters[i] == left->nodeid) {
|
||||||
LOG_ERROR("[%s] Removing pending ckpt from needed list (%u is leaving)",
|
LOG_ERROR("[%s] Removing pending ckpt from needed list (%u is leaving)",
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* 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,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
#ifndef _LVM_CLOG_CLUSTER_H
|
#ifndef _LVM_CLOG_CLUSTER_H
|
||||||
#define _LVM_CLOG_CLUSTER_H
|
#define _LVM_CLOG_CLUSTER_H
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* 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,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
#ifndef _LVM_CLOG_COMMON_H
|
#ifndef _LVM_CLOG_COMMON_H
|
||||||
#define _LVM_CLOG_COMMON_H
|
#define _LVM_CLOG_COMMON_H
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* 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,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "functions.h"
|
#include "functions.h"
|
||||||
@@ -32,13 +32,12 @@
|
|||||||
#define LOG_OFFSET 2
|
#define LOG_OFFSET 2
|
||||||
|
|
||||||
#define RESYNC_HISTORY 50
|
#define RESYNC_HISTORY 50
|
||||||
#define RESYNC_BUFLEN 128
|
|
||||||
//static char resync_history[RESYNC_HISTORY][128];
|
//static char resync_history[RESYNC_HISTORY][128];
|
||||||
//static int idx = 0;
|
//static int idx = 0;
|
||||||
#define LOG_SPRINT(_lc, f, arg...) do { \
|
#define LOG_SPRINT(_lc, f, arg...) do { \
|
||||||
lc->idx++; \
|
lc->idx++; \
|
||||||
lc->idx = lc->idx % RESYNC_HISTORY; \
|
lc->idx = lc->idx % RESYNC_HISTORY; \
|
||||||
snprintf(lc->resync_history[lc->idx], RESYNC_BUFLEN, f, ## arg); \
|
sprintf(lc->resync_history[lc->idx], f, ## arg); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
struct log_header {
|
struct log_header {
|
||||||
@@ -89,7 +88,7 @@ struct log_c {
|
|||||||
size_t disk_size; /* size of disk_buffer in bytes */
|
size_t disk_size; /* size of disk_buffer in bytes */
|
||||||
void *disk_buffer; /* aligned memory for O_DIRECT */
|
void *disk_buffer; /* aligned memory for O_DIRECT */
|
||||||
int idx;
|
int idx;
|
||||||
char resync_history[RESYNC_HISTORY][RESYNC_BUFLEN];
|
char resync_history[RESYNC_HISTORY][128];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mark_entry {
|
struct mark_entry {
|
||||||
@@ -573,12 +572,6 @@ static int clog_ctr(struct dm_ulog_request *rq)
|
|||||||
for (argc = 0, p = rq->data; (p = strstr(p, " ")); p++, argc++)
|
for (argc = 0, p = rq->data; (p = strstr(p, " ")); p++, argc++)
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
|
|
||||||
if (!argc) {
|
|
||||||
LOG_ERROR("Received constructor request with bad data %s",
|
|
||||||
rq->data);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
argv = malloc(argc * sizeof(char *));
|
argv = malloc(argc * sizeof(char *));
|
||||||
if (!argv)
|
if (!argv)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@@ -1451,7 +1444,7 @@ static int disk_status_info(struct log_c *lc, struct dm_ulog_request *rq)
|
|||||||
char *data = (char *)rq->data;
|
char *data = (char *)rq->data;
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
|
|
||||||
if (fstat(lc->disk_fd, &statbuf)) {
|
if(fstat(lc->disk_fd, &statbuf)) {
|
||||||
rq->error = -errno;
|
rq->error = -errno;
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
@@ -1514,7 +1507,7 @@ static int disk_status_table(struct log_c *lc, struct dm_ulog_request *rq)
|
|||||||
char *data = (char *)rq->data;
|
char *data = (char *)rq->data;
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
|
|
||||||
if (fstat(lc->disk_fd, &statbuf)) {
|
if(fstat(lc->disk_fd, &statbuf)) {
|
||||||
rq->error = -errno;
|
rq->error = -errno;
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* 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,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
#ifndef _LVM_CLOG_FUNCTIONS_H
|
#ifndef _LVM_CLOG_FUNCTIONS_H
|
||||||
#define _LVM_CLOG_FUNCTIONS_H
|
#define _LVM_CLOG_FUNCTIONS_H
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* 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,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "link_mon.h"
|
#include "link_mon.h"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* 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,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
#ifndef _LVM_CLOG_LINK_MON_H
|
#ifndef _LVM_CLOG_LINK_MON_H
|
||||||
#define _LVM_CLOG_LINK_MON_H
|
#define _LVM_CLOG_LINK_MON_H
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* 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,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* 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,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
#ifndef _LVM_CLOG_LOCAL_H
|
#ifndef _LVM_CLOG_LOCAL_H
|
||||||
#define _LVM_CLOG_LOCAL_H
|
#define _LVM_CLOG_LOCAL_H
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* 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,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* 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,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LVM_CLOG_LOGGING_H
|
#ifndef _LVM_CLOG_LOGGING_H
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# 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,
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
srcdir = @srcdir@
|
srcdir = @srcdir@
|
||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* 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,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __DMEVENTD_DOT_H__
|
#ifndef __DMEVENTD_DOT_H__
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
|
* Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is part of the device-mapper userspace tools.
|
* This file is part of the device-mapper userspace tools.
|
||||||
*
|
*
|
||||||
@@ -9,12 +9,12 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* 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,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "dm-logging.h"
|
|
||||||
#include "dmlib.h"
|
#include "dmlib.h"
|
||||||
#include "libdevmapper-event.h"
|
#include "libdevmapper-event.h"
|
||||||
|
//#include "libmultilog.h"
|
||||||
#include "dmeventd.h"
|
#include "dmeventd.h"
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -23,11 +23,7 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <arpa/inet.h> /* for htonl, ntohl */
|
#include <arpa/inet.h> /* for htonl, ntohl */
|
||||||
#include <pthread.h>
|
|
||||||
#include <syslog.h>
|
|
||||||
|
|
||||||
static int _debug_level = 0;
|
|
||||||
static int _use_syslog = 0;
|
|
||||||
static int _sequence_nr = 0;
|
static int _sequence_nr = 0;
|
||||||
|
|
||||||
struct dm_event_handler {
|
struct dm_event_handler {
|
||||||
@@ -198,7 +194,7 @@ static int _check_message_id(struct dm_event_daemon_message *msg)
|
|||||||
if ((sscanf(msg->data, "%d:%d", &pid, &seq_nr) != 2) ||
|
if ((sscanf(msg->data, "%d:%d", &pid, &seq_nr) != 2) ||
|
||||||
(pid != getpid()) || (seq_nr != _sequence_nr)) {
|
(pid != getpid()) || (seq_nr != _sequence_nr)) {
|
||||||
log_error("Ignoring out-of-sequence reply from dmeventd. "
|
log_error("Ignoring out-of-sequence reply from dmeventd. "
|
||||||
"Expected %d:%d but received %s.", getpid(),
|
"Expected %d:%d but received %s", getpid(),
|
||||||
_sequence_nr, msg->data);
|
_sequence_nr, msg->data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -233,7 +229,7 @@ static int _daemon_read(struct dm_event_fifos *fifos,
|
|||||||
FD_SET(fifos->server, &fds);
|
FD_SET(fifos->server, &fds);
|
||||||
ret = select(fifos->server + 1, &fds, NULL, NULL, &tval);
|
ret = select(fifos->server + 1, &fds, NULL, NULL, &tval);
|
||||||
if (ret < 0 && errno != EINTR) {
|
if (ret < 0 && errno != EINTR) {
|
||||||
log_error("Unable to read from event server.");
|
log_error("Unable to read from event server");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if ((ret == 0) && (i > 4) && !bytes) {
|
if ((ret == 0) && (i > 4) && !bytes) {
|
||||||
@@ -299,7 +295,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
|
|||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
continue;
|
continue;
|
||||||
log_error("Unable to talk to event daemon.");
|
log_error("Unable to talk to event daemon");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
@@ -308,7 +304,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
|
|||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if ((errno == EINTR) || (errno == EAGAIN))
|
if ((errno == EINTR) || (errno == EAGAIN))
|
||||||
continue;
|
continue;
|
||||||
log_error("Unable to talk to event daemon.");
|
log_error("Unable to talk to event daemon");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -320,7 +316,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
|
|||||||
FD_SET(fifos->client, &fds);
|
FD_SET(fifos->client, &fds);
|
||||||
ret = select(fifos->client + 1, NULL, &fds, NULL, NULL);
|
ret = select(fifos->client + 1, NULL, &fds, NULL, NULL);
|
||||||
if ((ret < 0) && (errno != EINTR)) {
|
if ((ret < 0) && (errno != EINTR)) {
|
||||||
log_error("Unable to talk to event daemon.");
|
log_error("Unable to talk to event daemon");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} while (ret < 1);
|
} while (ret < 1);
|
||||||
@@ -330,7 +326,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
|
|||||||
if ((errno == EINTR) || (errno == EAGAIN))
|
if ((errno == EINTR) || (errno == EAGAIN))
|
||||||
continue;
|
continue;
|
||||||
else {
|
else {
|
||||||
log_error("Unable to talk to event daemon.");
|
log_error("Unable to talk to event daemon");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -360,7 +356,7 @@ int daemon_talk(struct dm_event_fifos *fifos,
|
|||||||
getpid(), _sequence_nr,
|
getpid(), _sequence_nr,
|
||||||
dso_name ? : "-", dev_name ? : "-", evmask, timeout)))
|
dso_name ? : "-", dev_name ? : "-", evmask, timeout)))
|
||||||
< 0) {
|
< 0) {
|
||||||
log_error("_daemon_talk: message allocation failed.");
|
log_error("_daemon_talk: message allocation failed");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
msg->cmd = cmd;
|
msg->cmd = cmd;
|
||||||
@@ -412,55 +408,28 @@ static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos)
|
|||||||
char default_dmeventd_path[] = DMEVENTD_PATH;
|
char default_dmeventd_path[] = DMEVENTD_PATH;
|
||||||
char *args[] = { dmeventd_path ? : default_dmeventd_path, NULL };
|
char *args[] = { dmeventd_path ? : default_dmeventd_path, NULL };
|
||||||
|
|
||||||
/*
|
if (stat(fifos->client_path, &statbuf))
|
||||||
* FIXME Explicitly verify the code's requirement that client_path is secure:
|
goto start_server;
|
||||||
* - All parent directories owned by root without group/other write access unless sticky.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* If client fifo path exists, only use it if it is root-owned fifo mode 0600 */
|
if (!S_ISFIFO(statbuf.st_mode)) {
|
||||||
if ((lstat(fifos->client_path, &statbuf) < 0)) {
|
log_error("%s is not a fifo.", fifos->client_path);
|
||||||
if (errno == ENOENT)
|
|
||||||
/* Jump ahead if fifo does not already exist. */
|
|
||||||
goto start_server;
|
|
||||||
else {
|
|
||||||
log_sys_error("stat", fifos->client_path);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} else if (!S_ISFIFO(statbuf.st_mode)) {
|
|
||||||
log_error("%s must be a fifo.", fifos->client_path);
|
|
||||||
return 0;
|
|
||||||
} else if (statbuf.st_uid) {
|
|
||||||
log_error("%s must be owned by uid 0.", fifos->client_path);
|
|
||||||
return 0;
|
|
||||||
} else if (statbuf.st_mode & (S_IEXEC | S_IRWXG | S_IRWXO)) {
|
|
||||||
log_error("%s must have mode 0600.", fifos->client_path);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Anyone listening? If not, errno will be ENXIO */
|
/* Anyone listening? If not, errno will be ENXIO */
|
||||||
fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK);
|
fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK);
|
||||||
if (fifos->client >= 0) {
|
if (fifos->client >= 0) {
|
||||||
/* Should never happen if all the above checks passed. */
|
|
||||||
if ((fstat(fifos->client, &statbuf) < 0) ||
|
|
||||||
!S_ISFIFO(statbuf.st_mode) || statbuf.st_uid ||
|
|
||||||
(statbuf.st_mode & (S_IEXEC | S_IRWXG | S_IRWXO))) {
|
|
||||||
log_error("%s is no longer a secure root-owned fifo with mode 0600.", fifos->client_path);
|
|
||||||
if (close(fifos->client))
|
|
||||||
log_sys_debug("close", fifos->client_path);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* server is running and listening */
|
/* server is running and listening */
|
||||||
if (close(fifos->client))
|
if (close(fifos->client))
|
||||||
log_sys_debug("close", fifos->client_path);
|
log_sys_debug("close", fifos->client_path);
|
||||||
return 1;
|
return 1;
|
||||||
} else if (errno != ENXIO && errno != ENOENT) {
|
} else if (errno != ENXIO) {
|
||||||
/* problem */
|
/* problem */
|
||||||
log_sys_error("open", fifos->client_path);
|
log_sys_error("open", fifos->client_path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
start_server:
|
start_server:
|
||||||
/* server is not running */
|
/* server is not running */
|
||||||
|
|
||||||
if ((args[0][0] == '/') && stat(args[0], &statbuf)) {
|
if ((args[0][0] == '/') && stat(args[0], &statbuf)) {
|
||||||
@@ -475,11 +444,11 @@ start_server:
|
|||||||
|
|
||||||
else if (!pid) {
|
else if (!pid) {
|
||||||
execvp(args[0], args);
|
execvp(args[0], args);
|
||||||
log_error("Unable to exec dmeventd: %s.", strerror(errno));
|
log_error("Unable to exec dmeventd: %s", strerror(errno));
|
||||||
_exit(EXIT_FAILURE);
|
_exit(EXIT_FAILURE);
|
||||||
} else {
|
} else {
|
||||||
if (waitpid(pid, &status, 0) < 0)
|
if (waitpid(pid, &status, 0) < 0)
|
||||||
log_error("Unable to start dmeventd: %s.",
|
log_error("Unable to start dmeventd: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
else if (WEXITSTATUS(status))
|
else if (WEXITSTATUS(status))
|
||||||
log_error("Unable to start dmeventd.");
|
log_error("Unable to start dmeventd.");
|
||||||
@@ -552,7 +521,7 @@ static struct dm_task *_get_device_info(const struct dm_event_handler *dmevh)
|
|||||||
struct dm_info info;
|
struct dm_info info;
|
||||||
|
|
||||||
if (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
|
if (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
|
||||||
log_error("_get_device_info: dm_task creation for info failed.");
|
log_error("_get_device_info: dm_task creation for info failed");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -570,17 +539,17 @@ static struct dm_task *_get_device_info(const struct dm_event_handler *dmevh)
|
|||||||
|
|
||||||
/* FIXME Add name or uuid or devno to messages */
|
/* FIXME Add name or uuid or devno to messages */
|
||||||
if (!dm_task_run(dmt)) {
|
if (!dm_task_run(dmt)) {
|
||||||
log_error("_get_device_info: dm_task_run() failed.");
|
log_error("_get_device_info: dm_task_run() failed");
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dm_task_get_info(dmt, &info)) {
|
if (!dm_task_get_info(dmt, &info)) {
|
||||||
log_error("_get_device_info: failed to get info for device.");
|
log_error("_get_device_info: failed to get info for device");
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!info.exists) {
|
if (!info.exists) {
|
||||||
log_error("_get_device_info: %s%s%s%.0d%s%.0d%s%s: device not found.",
|
log_error("_get_device_info: %s%s%s%.0d%s%.0d%s%s: device not found",
|
||||||
dmevh->uuid ? : "",
|
dmevh->uuid ? : "",
|
||||||
(!dmevh->uuid && dmevh->dev_name) ? dmevh->dev_name : "",
|
(!dmevh->uuid && dmevh->dev_name) ? dmevh->dev_name : "",
|
||||||
(!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? "(" : "",
|
(!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? "(" : "",
|
||||||
@@ -614,8 +583,8 @@ static int _do_event(int cmd, char *dmeventd_path, struct dm_event_daemon_messag
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (!_init_client(dmeventd_path, &fifos)) {
|
if (!_init_client(dmeventd_path, &fifos)) {
|
||||||
ret = -ESRCH;
|
stack;
|
||||||
goto_out;
|
return -ESRCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = daemon_talk(&fifos, msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0);
|
ret = daemon_talk(&fifos, msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0);
|
||||||
@@ -625,7 +594,7 @@ static int _do_event(int cmd, char *dmeventd_path, struct dm_event_daemon_messag
|
|||||||
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
ret = daemon_talk(&fifos, msg, cmd, dso_name, dev_name, evmask, timeout);
|
ret = daemon_talk(&fifos, msg, cmd, dso_name, dev_name, evmask, timeout);
|
||||||
out:
|
|
||||||
/* what is the opposite of init? */
|
/* what is the opposite of init? */
|
||||||
fini_fifos(&fifos);
|
fini_fifos(&fifos);
|
||||||
|
|
||||||
@@ -649,12 +618,12 @@ int dm_event_register_handler(const struct dm_event_handler *dmevh)
|
|||||||
!strstr(dmevh->dso, "libdevmapper-event-lvm2snapshot.so") &&
|
!strstr(dmevh->dso, "libdevmapper-event-lvm2snapshot.so") &&
|
||||||
!strstr(dmevh->dso, "libdevmapper-event-lvm2mirror.so") &&
|
!strstr(dmevh->dso, "libdevmapper-event-lvm2mirror.so") &&
|
||||||
!strstr(dmevh->dso, "libdevmapper-event-lvm2raid.so"))
|
!strstr(dmevh->dso, "libdevmapper-event-lvm2raid.so"))
|
||||||
log_warn("WARNING: %s: dmeventd plugins are deprecated.", dmevh->dso);
|
log_warn("WARNING: %s: dmeventd plugins are deprecated", dmevh->dso);
|
||||||
|
|
||||||
|
|
||||||
if ((err = _do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, dmevh->dmeventd_path, &msg,
|
if ((err = _do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, dmevh->dmeventd_path, &msg,
|
||||||
dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) {
|
dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) {
|
||||||
log_error("%s: event registration failed: %s.",
|
log_error("%s: event registration failed: %s",
|
||||||
dm_task_get_name(dmt),
|
dm_task_get_name(dmt),
|
||||||
msg.data ? msg.data : strerror(-err));
|
msg.data ? msg.data : strerror(-err));
|
||||||
ret = 0;
|
ret = 0;
|
||||||
@@ -681,7 +650,7 @@ int dm_event_unregister_handler(const struct dm_event_handler *dmevh)
|
|||||||
|
|
||||||
if ((err = _do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, dmevh->dmeventd_path, &msg,
|
if ((err = _do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, dmevh->dmeventd_path, &msg,
|
||||||
dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) {
|
dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) {
|
||||||
log_error("%s: event deregistration failed: %s.",
|
log_error("%s: event deregistration failed: %s",
|
||||||
dm_task_get_name(dmt),
|
dm_task_get_name(dmt),
|
||||||
msg.data ? msg.data : strerror(-err));
|
msg.data ? msg.data : strerror(-err));
|
||||||
ret = 0;
|
ret = 0;
|
||||||
@@ -754,7 +723,6 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
|
|||||||
|
|
||||||
uuid = dm_task_get_uuid(dmt);
|
uuid = dm_task_get_uuid(dmt);
|
||||||
|
|
||||||
/* FIXME Distinguish errors connecting to daemon */
|
|
||||||
if (_do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE :
|
if (_do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE :
|
||||||
DM_EVENT_CMD_GET_REGISTERED_DEVICE, dmevh->dmeventd_path,
|
DM_EVENT_CMD_GET_REGISTERED_DEVICE, dmevh->dmeventd_path,
|
||||||
&msg, dmevh->dso, uuid, dmevh->mask, 0)) {
|
&msg, dmevh->dso, uuid, dmevh->mask, 0)) {
|
||||||
@@ -855,79 +823,6 @@ int dm_event_get_version(struct dm_event_fifos *fifos, int *version) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dm_event_log_set(int debug_log_level, int use_syslog)
|
|
||||||
{
|
|
||||||
_debug_level = debug_log_level;
|
|
||||||
_use_syslog = use_syslog;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
||||||
static time_t start = 0;
|
|
||||||
const char *indent = "";
|
|
||||||
FILE *stream = stdout;
|
|
||||||
int prio;
|
|
||||||
time_t now;
|
|
||||||
|
|
||||||
switch (level & ~(_LOG_STDERR | _LOG_ONCE)) {
|
|
||||||
case _LOG_DEBUG:
|
|
||||||
if (_debug_level < 3)
|
|
||||||
return;
|
|
||||||
prio = LOG_DEBUG;
|
|
||||||
indent = " ";
|
|
||||||
break;
|
|
||||||
case _LOG_INFO:
|
|
||||||
if (_debug_level < 2)
|
|
||||||
return;
|
|
||||||
prio = LOG_INFO;
|
|
||||||
indent = " ";
|
|
||||||
break;
|
|
||||||
case _LOG_NOTICE:
|
|
||||||
if (_debug_level < 1)
|
|
||||||
return;
|
|
||||||
prio = LOG_NOTICE;
|
|
||||||
indent = " ";
|
|
||||||
break;
|
|
||||||
case _LOG_WARN:
|
|
||||||
prio = LOG_WARNING;
|
|
||||||
break;
|
|
||||||
case _LOG_ERR:
|
|
||||||
prio = LOG_ERR;
|
|
||||||
stream = stderr;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
prio = LOG_CRIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Serialize to keep lines readable */
|
|
||||||
pthread_mutex_lock(&_log_mutex);
|
|
||||||
|
|
||||||
if (_use_syslog) {
|
|
||||||
vsyslog(prio, format, ap);
|
|
||||||
} else {
|
|
||||||
now = time(NULL);
|
|
||||||
if (!start)
|
|
||||||
start = now;
|
|
||||||
now -= start;
|
|
||||||
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);
|
|
||||||
fputc('\n', stream);
|
|
||||||
fflush(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&_log_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0 /* left out for now */
|
#if 0 /* left out for now */
|
||||||
|
|
||||||
static char *_skip_string(char *src, const int delimiter)
|
static char *_skip_string(char *src, const int delimiter)
|
||||||
@@ -961,7 +856,7 @@ int dm_event_get_timeout(const char *device_path, uint32_t *timeout)
|
|||||||
0, 0))) {
|
0, 0))) {
|
||||||
char *p = _skip_string(msg.data, ' ');
|
char *p = _skip_string(msg.data, ' ');
|
||||||
if (!p) {
|
if (!p) {
|
||||||
log_error("Malformed reply from dmeventd '%s'.",
|
log_error("malformed reply from dmeventd '%s'\n",
|
||||||
msg.data);
|
msg.data);
|
||||||
dm_free(msg.data);
|
dm_free(msg.data);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
|
* Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is part of the device-mapper userspace tools.
|
* This file is part of the device-mapper userspace tools.
|
||||||
*
|
*
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* 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,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -105,25 +105,6 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next);
|
|||||||
int dm_event_register_handler(const struct dm_event_handler *dmevh);
|
int dm_event_register_handler(const struct dm_event_handler *dmevh);
|
||||||
int dm_event_unregister_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);
|
|
||||||
|
|
||||||
/* Log messages acroding to current debug level */
|
|
||||||
__attribute__((format(printf, 6, 0)))
|
|
||||||
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);
|
|
||||||
/* Macro to route print_log do dm_event_log() */
|
|
||||||
#define DM_EVENT_LOG_FN(subsys) \
|
|
||||||
void print_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(subsys, level, file, line, dm_errno_or_class, format, ap);\
|
|
||||||
va_end(ap);\
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Prototypes for DSO interface, see dmeventd.c, struct dso_data for
|
/* Prototypes for DSO interface, see dmeventd.c, struct dso_data for
|
||||||
detailed descriptions. */
|
detailed descriptions. */
|
||||||
// FIXME misuse of bitmask as enum
|
// FIXME misuse of bitmask as enum
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program; if not, write to the Free Software Foundation,
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
srcdir = @srcdir@
|
srcdir = @srcdir@
|
||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program; if not, write to the Free Software Foundation,
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
srcdir = @srcdir@
|
srcdir = @srcdir@
|
||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
|
* Copyright (C) 2010 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is part of LVM2.
|
* This file is part of LVM2.
|
||||||
*
|
*
|
||||||
@@ -9,15 +9,19 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* 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,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
#include "dmeventd_lvm.h"
|
#include "log.h"
|
||||||
#include "libdevmapper-event.h"
|
|
||||||
#include "lvm2cmd.h"
|
#include "lvm2cmd.h"
|
||||||
|
#include "dmeventd_lvm.h"
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
|
||||||
|
extern int dmeventd_debug;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* register_device() is called first and performs initialisation.
|
* register_device() is called first and performs initialisation.
|
||||||
@@ -32,19 +36,48 @@ static int _register_count = 0;
|
|||||||
static struct dm_pool *_mem_pool = NULL;
|
static struct dm_pool *_mem_pool = NULL;
|
||||||
static void *_lvm_handle = NULL;
|
static void *_lvm_handle = NULL;
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
print_log(level, file, line, dm_errno_or_class, "%s", msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Currently only one event can be processed at a time.
|
* Currently only one event can be processed at a time.
|
||||||
*/
|
*/
|
||||||
static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME Do not pass things directly to syslog, rather use the existing logging
|
||||||
|
* facilities to sort logging ... however that mechanism needs to be somehow
|
||||||
|
* configurable and we don't have that option yet
|
||||||
|
*/
|
||||||
|
static void _temporary_log_fn(int level,
|
||||||
|
const char *file __attribute__((unused)),
|
||||||
|
int line __attribute__((unused)),
|
||||||
|
int dm_errno __attribute__((unused)),
|
||||||
|
const char *message)
|
||||||
|
{
|
||||||
|
level &= ~(_LOG_STDERR | _LOG_ONCE);
|
||||||
|
|
||||||
|
switch (level) {
|
||||||
|
case _LOG_DEBUG:
|
||||||
|
if (dmeventd_debug >= 3)
|
||||||
|
syslog(LOG_DEBUG, "%s", message);
|
||||||
|
break;
|
||||||
|
case _LOG_INFO:
|
||||||
|
if (dmeventd_debug >= 2)
|
||||||
|
syslog(LOG_INFO, "%s", message);
|
||||||
|
break;
|
||||||
|
case _LOG_NOTICE:
|
||||||
|
if (dmeventd_debug >= 1)
|
||||||
|
syslog(LOG_NOTICE, "%s", message);
|
||||||
|
break;
|
||||||
|
case _LOG_WARN:
|
||||||
|
syslog(LOG_WARNING, "%s", message);
|
||||||
|
break;
|
||||||
|
case _LOG_ERR:
|
||||||
|
syslog(LOG_ERR, "%s", message);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
syslog(LOG_CRIT, "%s", message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void dmeventd_lvm2_lock(void)
|
void dmeventd_lvm2_lock(void)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&_event_mutex);
|
pthread_mutex_lock(&_event_mutex);
|
||||||
@@ -61,26 +94,24 @@ int dmeventd_lvm2_init(void)
|
|||||||
|
|
||||||
pthread_mutex_lock(&_register_mutex);
|
pthread_mutex_lock(&_register_mutex);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Need some space for allocations. 1024 should be more
|
||||||
|
* than enough for what we need (device mapper name splitting)
|
||||||
|
*/
|
||||||
|
if (!_mem_pool && !(_mem_pool = dm_pool_create("mirror_dso", 1024)))
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (!_lvm_handle) {
|
if (!_lvm_handle) {
|
||||||
lvm2_log_fn(_lvm2_print_log);
|
if (!getenv("LVM_LOG_FILE_EPOCH"))
|
||||||
|
lvm2_log_fn(_temporary_log_fn);
|
||||||
if (!(_lvm_handle = lvm2_init()))
|
if (!(_lvm_handle = lvm2_init())) {
|
||||||
goto out;
|
dm_pool_destroy(_mem_pool);
|
||||||
|
_mem_pool = NULL;
|
||||||
/*
|
|
||||||
* Need some space for allocations. 1024 should be more
|
|
||||||
* than enough for what we need (device mapper name splitting)
|
|
||||||
*/
|
|
||||||
if (!_mem_pool && !(_mem_pool = dm_pool_create("mirror_dso", 1024))) {
|
|
||||||
lvm2_exit(_lvm_handle);
|
|
||||||
_lvm_handle = NULL;
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
lvm2_disable_dmeventd_monitoring(_lvm_handle);
|
lvm2_disable_dmeventd_monitoring(_lvm_handle);
|
||||||
/* FIXME Temporary: move to dmeventd core */
|
/* FIXME Temporary: move to dmeventd core */
|
||||||
lvm2_run(_lvm_handle, "_memlock_inc");
|
lvm2_run(_lvm_handle, "_memlock_inc");
|
||||||
log_debug("lvm plugin initilized.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_register_count++;
|
_register_count++;
|
||||||
@@ -96,13 +127,11 @@ void dmeventd_lvm2_exit(void)
|
|||||||
pthread_mutex_lock(&_register_mutex);
|
pthread_mutex_lock(&_register_mutex);
|
||||||
|
|
||||||
if (!--_register_count) {
|
if (!--_register_count) {
|
||||||
log_debug("lvm plugin shuting down.");
|
|
||||||
lvm2_run(_lvm_handle, "_memlock_dec");
|
lvm2_run(_lvm_handle, "_memlock_dec");
|
||||||
dm_pool_destroy(_mem_pool);
|
dm_pool_destroy(_mem_pool);
|
||||||
_mem_pool = NULL;
|
_mem_pool = NULL;
|
||||||
lvm2_exit(_lvm_handle);
|
lvm2_exit(_lvm_handle);
|
||||||
_lvm_handle = NULL;
|
_lvm_handle = NULL;
|
||||||
log_debug("lvm plugin exited.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&_register_mutex);
|
pthread_mutex_unlock(&_register_mutex);
|
||||||
@@ -125,8 +154,8 @@ int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
|
|||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!dm_split_lvm_name(mem, device, &vg, &lv, &layer)) {
|
if (!dm_split_lvm_name(mem, device, &vg, &lv, &layer)) {
|
||||||
log_error("Unable to determine VG name from %s.",
|
syslog(LOG_ERR, "Unable to determine VG name from %s.\n",
|
||||||
device);
|
device);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,7 +169,7 @@ int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
|
|||||||
dm_pool_free(mem, vg);
|
dm_pool_free(mem, vg);
|
||||||
|
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_error("Unable to form LVM command. (too long).");
|
syslog(LOG_ERR, "Unable to form LVM command. (too long).\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
|
* Copyright (C) 2010 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is part of LVM2.
|
* This file is part of LVM2.
|
||||||
*
|
*
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* 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,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -39,36 +39,4 @@ struct dm_pool *dmeventd_lvm2_pool(void);
|
|||||||
int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
|
int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
|
||||||
const char *cmd, const char *device);
|
const char *cmd, const char *device);
|
||||||
|
|
||||||
#define dmeventd_lvm2_run_with_lock(cmdline) \
|
|
||||||
({\
|
|
||||||
int rc;\
|
|
||||||
dmeventd_lvm2_lock();\
|
|
||||||
rc = dmeventd_lvm2_run(cmdline);\
|
|
||||||
dmeventd_lvm2_unlock();\
|
|
||||||
rc;\
|
|
||||||
})
|
|
||||||
|
|
||||||
#define dmeventd_lvm2_init_with_pool(name, st) \
|
|
||||||
({\
|
|
||||||
struct dm_pool *mem;\
|
|
||||||
st = NULL;\
|
|
||||||
if (dmeventd_lvm2_init()) {\
|
|
||||||
if ((mem = dm_pool_create(name, 2048)) &&\
|
|
||||||
(st = dm_pool_zalloc(mem, sizeof(*st))))\
|
|
||||||
st->mem = mem;\
|
|
||||||
else {\
|
|
||||||
if (mem)\
|
|
||||||
dm_pool_destroy(mem);\
|
|
||||||
dmeventd_lvm2_exit();\
|
|
||||||
}\
|
|
||||||
}\
|
|
||||||
st;\
|
|
||||||
})
|
|
||||||
|
|
||||||
#define dmeventd_lvm2_exit_with_pool(pool) \
|
|
||||||
do {\
|
|
||||||
dm_pool_destroy(pool->mem);\
|
|
||||||
dmeventd_lvm2_exit();\
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
#endif /* _DMEVENTD_LVMWRAP_H */
|
#endif /* _DMEVENTD_LVMWRAP_H */
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program; if not, write to the Free Software Foundation,
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
srcdir = @srcdir@
|
srcdir = @srcdir@
|
||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
|
* Copyright (C) 2005-2012 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is part of LVM2.
|
* This file is part of LVM2.
|
||||||
*
|
*
|
||||||
@@ -9,31 +9,26 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* 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,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
|
|
||||||
#include "libdevmapper-event.h"
|
#include "libdevmapper-event.h"
|
||||||
#include "dmeventd_lvm.h"
|
#include "dmeventd_lvm.h"
|
||||||
#include "activate.h" /* For TARGET_NAME* */
|
#include "defaults.h"
|
||||||
|
|
||||||
|
#include <syslog.h> /* FIXME Replace syslog with multilog */
|
||||||
|
/* FIXME Missing openlog? */
|
||||||
|
/* FIXME Replace most syslogs with log_error() style messages and add complete context. */
|
||||||
/* FIXME Reformat to 80 char lines. */
|
/* FIXME Reformat to 80 char lines. */
|
||||||
|
|
||||||
#define ME_IGNORE 0
|
#define ME_IGNORE 0
|
||||||
#define ME_INSYNC 1
|
#define ME_INSYNC 1
|
||||||
#define ME_FAILURE 2
|
#define ME_FAILURE 2
|
||||||
|
|
||||||
struct dso_state {
|
static int _process_status_code(const char status_code, const char *dev_name,
|
||||||
struct dm_pool *mem;
|
const char *dev_type, int r)
|
||||||
char cmd_lvscan[512];
|
|
||||||
char cmd_lvconvert[512];
|
|
||||||
};
|
|
||||||
|
|
||||||
DM_EVENT_LOG_FN("mirr")
|
|
||||||
|
|
||||||
static void _process_status_code(dm_status_mirror_health_t health,
|
|
||||||
uint32_t major, uint32_t minor,
|
|
||||||
const char *dev_type, int *r)
|
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* A => Alive - No failures
|
* A => Alive - No failures
|
||||||
@@ -43,181 +38,206 @@ static void _process_status_code(dm_status_mirror_health_t health,
|
|||||||
* R => Read - A read failure occurred, mirror data unaffected
|
* R => Read - A read failure occurred, mirror data unaffected
|
||||||
* U => Unclassified failure (bug)
|
* U => Unclassified failure (bug)
|
||||||
*/
|
*/
|
||||||
switch (health) {
|
if (status_code == 'F') {
|
||||||
case DM_STATUS_MIRROR_ALIVE:
|
syslog(LOG_ERR, "%s device %s flush failed.",
|
||||||
return;
|
dev_type, dev_name);
|
||||||
case DM_STATUS_MIRROR_FLUSH_FAILED:
|
r = ME_FAILURE;
|
||||||
log_error("%s device %u:%u flush failed.",
|
} else if (status_code == 'S')
|
||||||
dev_type, major, minor);
|
syslog(LOG_ERR, "%s device %s sync failed.",
|
||||||
*r = ME_FAILURE;
|
dev_type, dev_name);
|
||||||
break;
|
else if (status_code == 'R')
|
||||||
case DM_STATUS_MIRROR_SYNC_FAILED:
|
syslog(LOG_ERR, "%s device %s read failed.",
|
||||||
log_error("%s device %u:%u sync failed.",
|
dev_type, dev_name);
|
||||||
dev_type, major, minor);
|
else if (status_code != 'A') {
|
||||||
break;
|
syslog(LOG_ERR, "%s device %s has failed (%c).",
|
||||||
case DM_STATUS_MIRROR_READ_FAILED:
|
dev_type, dev_name, status_code);
|
||||||
log_error("%s device %u:%u read failed.",
|
r = ME_FAILURE;
|
||||||
dev_type, major, minor);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
log_error("%s device %u:%u has failed (%c).",
|
|
||||||
dev_type, major, minor, (char)health);
|
|
||||||
*r = ME_FAILURE;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static int _get_mirror_event(struct dso_state *state, char *params)
|
|
||||||
{
|
|
||||||
int r = ME_INSYNC;
|
|
||||||
unsigned i;
|
|
||||||
struct dm_status_mirror *ms;
|
|
||||||
|
|
||||||
if (!dm_get_status_mirror(state->mem, params, &ms))
|
|
||||||
goto_out;
|
|
||||||
|
|
||||||
/* Check for bad mirror devices */
|
|
||||||
for (i = 0; i < ms->dev_count; ++i)
|
|
||||||
_process_status_code(ms->devs[i].health,
|
|
||||||
ms->devs[i].major, ms->devs[i].minor,
|
|
||||||
i ? "Secondary mirror" : "Primary mirror", &r);
|
|
||||||
|
|
||||||
/* Check for bad disk log device */
|
|
||||||
for (i = 0; i < ms->log_count; ++i)
|
|
||||||
_process_status_code(ms->logs[i].health,
|
|
||||||
ms->logs[i].major, ms->logs[i].minor,
|
|
||||||
"Log", &r);
|
|
||||||
|
|
||||||
/* Ignore if not in-sync */
|
|
||||||
if ((r == ME_INSYNC) && (ms->insync_regions != ms->total_regions))
|
|
||||||
r = ME_IGNORE;
|
|
||||||
|
|
||||||
dm_pool_free(state->mem, ms);
|
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _get_mirror_event(char *params)
|
||||||
|
{
|
||||||
|
int i, r = ME_INSYNC;
|
||||||
|
char **args = NULL;
|
||||||
|
char *dev_status_str;
|
||||||
|
char *log_status_str;
|
||||||
|
char *sync_str;
|
||||||
|
char *p = NULL;
|
||||||
|
int log_argc, num_devs;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* dm core parms: 0 409600 mirror
|
||||||
|
* Mirror core parms: 2 253:4 253:5 400/400
|
||||||
|
* New-style failure params: 1 AA
|
||||||
|
* New-style log params: 3 cluster 253:3 A
|
||||||
|
* or 3 disk 253:3 A
|
||||||
|
* or 1 core
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* number of devices */
|
||||||
|
if (!dm_split_words(params, 1, 0, &p))
|
||||||
|
goto out_parse;
|
||||||
|
|
||||||
|
if (!(num_devs = atoi(p)) ||
|
||||||
|
(num_devs > DEFAULT_MIRROR_MAX_IMAGES) || (num_devs < 0))
|
||||||
|
goto out_parse;
|
||||||
|
p += strlen(p) + 1;
|
||||||
|
|
||||||
|
/* devices names + "400/400" + "1 AA" + 1 or 3 log parms + NULL */
|
||||||
|
args = dm_malloc((num_devs + 7) * sizeof(char *));
|
||||||
|
if (!args || dm_split_words(p, num_devs + 7, 0, args) < num_devs + 5)
|
||||||
|
goto out_parse;
|
||||||
|
|
||||||
|
/* FIXME: Code differs from lib/mirror/mirrored.c */
|
||||||
|
dev_status_str = args[2 + num_devs];
|
||||||
|
log_argc = atoi(args[3 + num_devs]);
|
||||||
|
log_status_str = args[3 + num_devs + log_argc];
|
||||||
|
sync_str = args[num_devs];
|
||||||
|
|
||||||
|
/* Check for bad mirror devices */
|
||||||
|
for (i = 0; i < num_devs; i++)
|
||||||
|
r = _process_status_code(dev_status_str[i], args[i],
|
||||||
|
i ? "Secondary mirror" : "Primary mirror", r);
|
||||||
|
|
||||||
|
/* Check for bad disk log device */
|
||||||
|
if (log_argc > 1)
|
||||||
|
r = _process_status_code(log_status_str[0],
|
||||||
|
args[2 + num_devs + log_argc],
|
||||||
|
"Log", r);
|
||||||
|
|
||||||
|
if (r == ME_FAILURE)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
p = strstr(sync_str, "/");
|
||||||
|
if (p) {
|
||||||
|
p[0] = '\0';
|
||||||
|
if (strcmp(sync_str, p+1))
|
||||||
|
r = ME_IGNORE;
|
||||||
|
p[0] = '/';
|
||||||
|
} else
|
||||||
|
goto out_parse;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
log_error("Unable to parse mirror status string.");
|
dm_free(args);
|
||||||
|
return r;
|
||||||
|
|
||||||
|
out_parse:
|
||||||
|
dm_free(args);
|
||||||
|
syslog(LOG_ERR, "Unable to parse mirror status string.");
|
||||||
return ME_IGNORE;
|
return ME_IGNORE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _remove_failed_devices(const char *cmd_lvscan, const char *cmd_lvconvert)
|
static int _remove_failed_devices(const char *device)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
#define CMD_SIZE 256 /* FIXME Use system restriction */
|
||||||
|
char cmd_str[CMD_SIZE];
|
||||||
|
|
||||||
if (!dmeventd_lvm2_run_with_lock(cmd_lvscan))
|
if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str),
|
||||||
log_info("Re-scan of mirrored device failed.");
|
"lvscan --cache", device))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
r = dmeventd_lvm2_run(cmd_str);
|
||||||
|
|
||||||
|
if (!r)
|
||||||
|
syslog(LOG_INFO, "Re-scan of mirror device %s failed.", device);
|
||||||
|
|
||||||
|
if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str),
|
||||||
|
"lvconvert --config devices{ignore_suspended_devices=1} "
|
||||||
|
"--repair --use-policies", device))
|
||||||
|
return -ENAMETOOLONG; /* FIXME Replace with generic error return - reason for failure has already got logged */
|
||||||
|
|
||||||
/* if repair goes OK, report success even if lvscan has failed */
|
/* if repair goes OK, report success even if lvscan has failed */
|
||||||
r = dmeventd_lvm2_run_with_lock(cmd_lvconvert);
|
r = dmeventd_lvm2_run(cmd_str);
|
||||||
|
|
||||||
log_info("Repair of mirrored device %s.",
|
syslog(LOG_INFO, "Repair of mirrored device %s %s.", device,
|
||||||
(r) ? "finished successfully" : "failed");
|
(r) ? "finished successfully" : "failed");
|
||||||
|
|
||||||
return r;
|
return (r) ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_event(struct dm_task *dmt,
|
void process_event(struct dm_task *dmt,
|
||||||
enum dm_event_mask event __attribute__((unused)),
|
enum dm_event_mask event __attribute__((unused)),
|
||||||
void **user)
|
void **unused __attribute__((unused)))
|
||||||
{
|
{
|
||||||
struct dso_state *state = *user;
|
|
||||||
void *next = NULL;
|
void *next = NULL;
|
||||||
uint64_t start, length;
|
uint64_t start, length;
|
||||||
char *target_type = NULL;
|
char *target_type = NULL;
|
||||||
char *params;
|
char *params;
|
||||||
const char *device = dm_task_get_name(dmt);
|
const char *device = dm_task_get_name(dmt);
|
||||||
|
|
||||||
|
dmeventd_lvm2_lock();
|
||||||
|
|
||||||
do {
|
do {
|
||||||
next = dm_get_next_target(dmt, next, &start, &length,
|
next = dm_get_next_target(dmt, next, &start, &length,
|
||||||
&target_type, ¶ms);
|
&target_type, ¶ms);
|
||||||
|
|
||||||
if (!target_type) {
|
if (!target_type) {
|
||||||
log_info("%s mapping lost.", device);
|
syslog(LOG_INFO, "%s mapping lost.", device);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(target_type, TARGET_NAME_MIRROR)) {
|
if (strcmp(target_type, "mirror")) {
|
||||||
log_info("%s has unmirrored portion.", device);
|
syslog(LOG_INFO, "%s has unmirrored portion.", device);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(_get_mirror_event(state, params)) {
|
switch(_get_mirror_event(params)) {
|
||||||
case ME_INSYNC:
|
case ME_INSYNC:
|
||||||
/* FIXME: all we really know is that this
|
/* FIXME: all we really know is that this
|
||||||
_part_ of the device is in sync
|
_part_ of the device is in sync
|
||||||
Also, this is not an error
|
Also, this is not an error
|
||||||
*/
|
*/
|
||||||
log_notice("%s is now in-sync.", device);
|
syslog(LOG_NOTICE, "%s is now in-sync.", device);
|
||||||
break;
|
break;
|
||||||
case ME_FAILURE:
|
case ME_FAILURE:
|
||||||
log_error("Device failure in %s.", device);
|
syslog(LOG_ERR, "Device failure in %s.", device);
|
||||||
if (!_remove_failed_devices(state->cmd_lvscan,
|
if (_remove_failed_devices(device))
|
||||||
state->cmd_lvconvert))
|
|
||||||
/* FIXME Why are all the error return codes unused? Get rid of them? */
|
/* FIXME Why are all the error return codes unused? Get rid of them? */
|
||||||
log_error("Failed to remove faulty devices in %s.",
|
syslog(LOG_ERR, "Failed to remove faulty devices in %s.",
|
||||||
device);
|
device);
|
||||||
/* Should check before warning user that device is now linear
|
/* Should check before warning user that device is now linear
|
||||||
else
|
else
|
||||||
log_notice("%s is now a linear device.",
|
syslog(LOG_NOTICE, "%s is now a linear device.\n",
|
||||||
device);
|
device);
|
||||||
*/
|
*/
|
||||||
break;
|
break;
|
||||||
case ME_IGNORE:
|
case ME_IGNORE:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* FIXME Provide value then! */
|
/* FIXME Provide value then! */
|
||||||
log_info("Unknown event received.");
|
syslog(LOG_INFO, "Unknown event received.");
|
||||||
}
|
}
|
||||||
} while (next);
|
} while (next);
|
||||||
|
|
||||||
|
dmeventd_lvm2_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
int register_device(const char *device,
|
int register_device(const char *device,
|
||||||
const char *uuid __attribute__((unused)),
|
const char *uuid __attribute__((unused)),
|
||||||
int major __attribute__((unused)),
|
int major __attribute__((unused)),
|
||||||
int minor __attribute__((unused)),
|
int minor __attribute__((unused)),
|
||||||
void **user)
|
void **unused __attribute__((unused)))
|
||||||
{
|
{
|
||||||
struct dso_state *state;
|
if (!dmeventd_lvm2_init())
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (!dmeventd_lvm2_init_with_pool("mirror_state", state))
|
syslog(LOG_INFO, "Monitoring mirror device %s for events.", device);
|
||||||
goto_bad;
|
|
||||||
|
|
||||||
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvscan, sizeof(state->cmd_lvscan),
|
|
||||||
"lvscan --cache", device)) {
|
|
||||||
dmeventd_lvm2_exit_with_pool(state);
|
|
||||||
goto_bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvconvert, sizeof(state->cmd_lvconvert),
|
|
||||||
"lvconvert --repair --use-policies", device)) {
|
|
||||||
dmeventd_lvm2_exit_with_pool(state);
|
|
||||||
goto_bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
*user = state;
|
|
||||||
|
|
||||||
log_info("Monitoring mirror device %s for events.", device);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
bad:
|
|
||||||
log_error("Failed to monitor mirror %s.", device);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int unregister_device(const char *device,
|
int unregister_device(const char *device,
|
||||||
const char *uuid __attribute__((unused)),
|
const char *uuid __attribute__((unused)),
|
||||||
int major __attribute__((unused)),
|
int major __attribute__((unused)),
|
||||||
int minor __attribute__((unused)),
|
int minor __attribute__((unused)),
|
||||||
void **user)
|
void **unused __attribute__((unused)))
|
||||||
{
|
{
|
||||||
struct dso_state *state = *user;
|
syslog(LOG_INFO, "No longer monitoring mirror device %s for events.",
|
||||||
|
device);
|
||||||
dmeventd_lvm2_exit_with_pool(state);
|
dmeventd_lvm2_exit();
|
||||||
log_info("No longer monitoring mirror device %s for events.",
|
|
||||||
device);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program; if not, write to the Free Software Foundation,
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
srcdir = @srcdir@
|
srcdir = @srcdir@
|
||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
|
* Copyright (C) 2005-2011 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is part of LVM2.
|
* This file is part of LVM2.
|
||||||
*
|
*
|
||||||
@@ -9,137 +9,172 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* 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,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
#include "dmeventd_lvm.h"
|
|
||||||
#include "libdevmapper-event.h"
|
#include "libdevmapper-event.h"
|
||||||
|
#include "dmeventd_lvm.h"
|
||||||
|
|
||||||
struct dso_state {
|
#include <syslog.h> /* FIXME Replace syslog with multilog */
|
||||||
struct dm_pool *mem;
|
/* FIXME Missing openlog? */
|
||||||
char cmd_lvscan[512];
|
/* FIXME Replace most syslogs with log_error() style messages and add complete context. */
|
||||||
char cmd_lvconvert[512];
|
|
||||||
int failed;
|
|
||||||
};
|
|
||||||
|
|
||||||
DM_EVENT_LOG_FN("raid")
|
|
||||||
|
|
||||||
/* FIXME Reformat to 80 char lines. */
|
/* FIXME Reformat to 80 char lines. */
|
||||||
|
|
||||||
static int _process_raid_event(struct dso_state *state, char *params, const char *device)
|
/*
|
||||||
|
* run_repair is a close copy to
|
||||||
|
* plugins/mirror/dmeventd_mirror.c:_remove_failed_devices()
|
||||||
|
*/
|
||||||
|
static int run_repair(const char *device)
|
||||||
{
|
{
|
||||||
struct dm_status_raid *status;
|
int r;
|
||||||
const char *d;
|
#define CMD_SIZE 256 /* FIXME Use system restriction */
|
||||||
|
char cmd_str[CMD_SIZE];
|
||||||
|
|
||||||
if (!dm_get_status_raid(state->mem, params, &status)) {
|
if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str),
|
||||||
log_error("Failed to process status line for %s.", device);
|
"lvscan --cache", device))
|
||||||
return 0;
|
return -1;
|
||||||
|
|
||||||
|
r = dmeventd_lvm2_run(cmd_str);
|
||||||
|
|
||||||
|
if (!r)
|
||||||
|
syslog(LOG_INFO, "Re-scan of RAID device %s failed.", device);
|
||||||
|
|
||||||
|
if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str),
|
||||||
|
"lvconvert --config devices{ignore_suspended_devices=1} "
|
||||||
|
"--repair --use-policies", device))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* if repair goes OK, report success even if lvscan has failed */
|
||||||
|
r = dmeventd_lvm2_run(cmd_str);
|
||||||
|
|
||||||
|
if (!r)
|
||||||
|
syslog(LOG_INFO, "Repair of RAID device %s failed.", device);
|
||||||
|
|
||||||
|
return (r) ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _process_raid_event(char *params, const char *device)
|
||||||
|
{
|
||||||
|
int i, n, failure = 0;
|
||||||
|
char *p, *a[4];
|
||||||
|
char *raid_type;
|
||||||
|
char *num_devices;
|
||||||
|
char *health_chars;
|
||||||
|
char *resync_ratio;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RAID parms: <raid_type> <#raid_disks> \
|
||||||
|
* <health chars> <resync ratio>
|
||||||
|
*/
|
||||||
|
if (!dm_split_words(params, 4, 0, a)) {
|
||||||
|
syslog(LOG_ERR, "Failed to process status line for %s\n",
|
||||||
|
device);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
raid_type = a[0];
|
||||||
|
num_devices = a[1];
|
||||||
|
health_chars = a[2];
|
||||||
|
resync_ratio = a[3];
|
||||||
|
|
||||||
|
if (!(n = atoi(num_devices))) {
|
||||||
|
syslog(LOG_ERR, "Failed to parse number of devices for %s: %s",
|
||||||
|
device, num_devices);
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((d = strchr(status->dev_health, 'D'))) {
|
for (i = 0; i < n; i++) {
|
||||||
if (state->failed)
|
switch (health_chars[i]) {
|
||||||
goto out; /* already reported */
|
case 'A':
|
||||||
|
/* Device is 'A'live and well */
|
||||||
log_error("Device #%d of %s array, %s, has failed.",
|
case 'a':
|
||||||
(int)(d - status->dev_health),
|
/* Device is 'a'live, but not yet in-sync */
|
||||||
status->raid_type, device);
|
break;
|
||||||
|
case 'D':
|
||||||
state->failed = 1;
|
syslog(LOG_ERR,
|
||||||
if (!dmeventd_lvm2_run_with_lock(state->cmd_lvscan))
|
"Device #%d of %s array, %s, has failed.",
|
||||||
log_warn("WARNING: Re-scan of RAID device %s failed.", device);
|
i, raid_type, device);
|
||||||
|
failure++;
|
||||||
/* if repair goes OK, report success even if lvscan has failed */
|
break;
|
||||||
if (!dmeventd_lvm2_run_with_lock(state->cmd_lvconvert)) {
|
default:
|
||||||
log_info("Repair of RAID device %s failed.", device);
|
/* Unhandled character returned from kernel */
|
||||||
dm_pool_free(state->mem, status);
|
break;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
} else {
|
if (failure)
|
||||||
state->failed = 0;
|
return run_repair(device);
|
||||||
log_info("%s array, %s, is %s in-sync.",
|
|
||||||
status->raid_type, device,
|
|
||||||
(status->insync_regions == status->total_regions) ? "now" : "not");
|
|
||||||
}
|
}
|
||||||
out:
|
|
||||||
dm_pool_free(state->mem, status);
|
|
||||||
|
|
||||||
return 1;
|
p = strstr(resync_ratio, "/");
|
||||||
|
if (!p) {
|
||||||
|
syslog(LOG_ERR, "Failed to parse resync_ratio for %s: %s",
|
||||||
|
device, resync_ratio);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
p[0] = '\0';
|
||||||
|
syslog(LOG_INFO, "%s array, %s, is %s in-sync.",
|
||||||
|
raid_type, device, strcmp(resync_ratio, p+1) ? "not" : "now");
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_event(struct dm_task *dmt,
|
void process_event(struct dm_task *dmt,
|
||||||
enum dm_event_mask event __attribute__((unused)),
|
enum dm_event_mask event __attribute__((unused)),
|
||||||
void **user)
|
void **unused __attribute__((unused)))
|
||||||
{
|
{
|
||||||
struct dso_state *state = *user;
|
|
||||||
void *next = NULL;
|
void *next = NULL;
|
||||||
uint64_t start, length;
|
uint64_t start, length;
|
||||||
char *target_type = NULL;
|
char *target_type = NULL;
|
||||||
char *params;
|
char *params;
|
||||||
const char *device = dm_task_get_name(dmt);
|
const char *device = dm_task_get_name(dmt);
|
||||||
|
|
||||||
|
dmeventd_lvm2_lock();
|
||||||
|
|
||||||
do {
|
do {
|
||||||
next = dm_get_next_target(dmt, next, &start, &length,
|
next = dm_get_next_target(dmt, next, &start, &length,
|
||||||
&target_type, ¶ms);
|
&target_type, ¶ms);
|
||||||
|
|
||||||
if (!target_type) {
|
if (!target_type) {
|
||||||
log_info("%s mapping lost.", device);
|
syslog(LOG_INFO, "%s mapping lost.", device);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(target_type, "raid")) {
|
if (strcmp(target_type, "raid")) {
|
||||||
log_info("%s has non-raid portion.", device);
|
syslog(LOG_INFO, "%s has non-raid portion.", device);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_process_raid_event(state, params, device))
|
if (_process_raid_event(params, device))
|
||||||
log_error("Failed to process event for %s.",
|
syslog(LOG_ERR, "Failed to process event for %s",
|
||||||
device);
|
device);
|
||||||
} while (next);
|
} while (next);
|
||||||
|
|
||||||
|
dmeventd_lvm2_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
int register_device(const char *device,
|
int register_device(const char *device,
|
||||||
const char *uuid __attribute__((unused)),
|
const char *uuid __attribute__((unused)),
|
||||||
int major __attribute__((unused)),
|
int major __attribute__((unused)),
|
||||||
int minor __attribute__((unused)),
|
int minor __attribute__((unused)),
|
||||||
void **user)
|
void **unused __attribute__((unused)))
|
||||||
{
|
{
|
||||||
struct dso_state *state;
|
if (!dmeventd_lvm2_init())
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (!dmeventd_lvm2_init_with_pool("raid_state", state))
|
syslog(LOG_INFO, "Monitoring RAID device %s for events.", device);
|
||||||
goto_bad;
|
|
||||||
|
|
||||||
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvscan, sizeof(state->cmd_lvscan),
|
|
||||||
"lvscan --cache", device) ||
|
|
||||||
!dmeventd_lvm2_command(state->mem, state->cmd_lvconvert, sizeof(state->cmd_lvconvert),
|
|
||||||
"lvconvert --config devices{ignore_suspended_devices=1} "
|
|
||||||
"--repair --use-policies", device)) {
|
|
||||||
dmeventd_lvm2_exit_with_pool(state);
|
|
||||||
goto_bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
*user = state;
|
|
||||||
|
|
||||||
log_info("Monitoring RAID device %s for events.", device);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
bad:
|
|
||||||
log_error("Failed to monitor RAID %s.", device);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int unregister_device(const char *device,
|
int unregister_device(const char *device,
|
||||||
const char *uuid __attribute__((unused)),
|
const char *uuid __attribute__((unused)),
|
||||||
int major __attribute__((unused)),
|
int major __attribute__((unused)),
|
||||||
int minor __attribute__((unused)),
|
int minor __attribute__((unused)),
|
||||||
void **user)
|
void **unused __attribute__((unused)))
|
||||||
{
|
{
|
||||||
struct dso_state *state = *user;
|
syslog(LOG_INFO, "No longer monitoring RAID device %s for events.",
|
||||||
|
device);
|
||||||
dmeventd_lvm2_exit_with_pool(state);
|
dmeventd_lvm2_exit();
|
||||||
log_info("No longer monitoring RAID device %s for events.",
|
|
||||||
device);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program; if not, write to the Free Software Foundation,
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
srcdir = @srcdir@
|
srcdir = @srcdir@
|
||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2007-2015 Red Hat, Inc. All rights reserved.
|
* Copyright (C) 2007-2011 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is part of LVM2.
|
* This file is part of LVM2.
|
||||||
*
|
*
|
||||||
@@ -9,35 +9,35 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* 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,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
#include "dmeventd_lvm.h"
|
|
||||||
#include "libdevmapper-event.h"
|
#include "libdevmapper-event.h"
|
||||||
|
#include "dmeventd_lvm.h"
|
||||||
|
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
#include <syslog.h> /* FIXME Replace syslog with multilog */
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <pthread.h>
|
/* FIXME Missing openlog? */
|
||||||
|
|
||||||
/* First warning when snapshot is 80% full. */
|
/* First warning when snapshot is 80% full. */
|
||||||
#define WARNING_THRESH (DM_PERCENT_1 * 80)
|
#define WARNING_THRESH 80
|
||||||
/* Run a check every 5%. */
|
/* Run a check every 5%. */
|
||||||
#define CHECK_STEP (DM_PERCENT_1 * 5)
|
#define CHECK_STEP 5
|
||||||
/* Do not bother checking snapshots less than 50% full. */
|
/* Do not bother checking snapshots less than 50% full. */
|
||||||
#define CHECK_MINIMUM (DM_PERCENT_1 * 50)
|
#define CHECK_MINIMUM 50
|
||||||
|
|
||||||
#define UMOUNT_COMMAND "/bin/umount"
|
#define UMOUNT_COMMAND "/bin/umount"
|
||||||
|
|
||||||
struct dso_state {
|
struct dso_state {
|
||||||
struct dm_pool *mem;
|
struct dm_pool *mem;
|
||||||
dm_percent_t percent_check;
|
int percent_check;
|
||||||
uint64_t known_size;
|
uint64_t known_size;
|
||||||
char cmd_lvextend[512];
|
char cmd_str[1024];
|
||||||
};
|
};
|
||||||
|
|
||||||
DM_EVENT_LOG_FN("snap")
|
|
||||||
|
|
||||||
static int _run(const char *cmd, ...)
|
static int _run(const char *cmd, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
@@ -62,7 +62,7 @@ static int _run(const char *cmd, ...)
|
|||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
execvp(cmd, (char **)argv);
|
execvp(cmd, (char **)argv);
|
||||||
log_sys_error("exec", cmd);
|
syslog(LOG_ERR, "Failed to execute %s: %s.\n", cmd, strerror(errno));
|
||||||
exit(127);
|
exit(127);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,56 +81,18 @@ static int _run(const char *cmd, ...)
|
|||||||
|
|
||||||
static int _extend(const char *cmd)
|
static int _extend(const char *cmd)
|
||||||
{
|
{
|
||||||
log_debug("Extending snapshot via %s.", cmd);
|
return dmeventd_lvm2_run(cmd);
|
||||||
return dmeventd_lvm2_run_with_lock(cmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SNAPSHOT_REMOVE
|
|
||||||
/* Remove invalid snapshot from dm-table */
|
|
||||||
/* Experimental for now and not used by default */
|
|
||||||
static int _remove(const char *uuid)
|
|
||||||
{
|
|
||||||
int r = 1;
|
|
||||||
uint32_t cookie = 0;
|
|
||||||
struct dm_task *dmt;
|
|
||||||
|
|
||||||
if (!(dmt = dm_task_create(DM_DEVICE_REMOVE)))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!dm_task_set_uuid(dmt, uuid)) {
|
|
||||||
r = 0;
|
|
||||||
goto_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
dm_task_retry_remove(dmt);
|
|
||||||
|
|
||||||
if (!dm_task_set_cookie(dmt, &cookie, 0)) {
|
|
||||||
r = 0;
|
|
||||||
goto_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dm_task_run(dmt)) {
|
|
||||||
r = 0;
|
|
||||||
goto_out;
|
|
||||||
}
|
|
||||||
out:
|
|
||||||
dm_task_destroy(dmt);
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
#endif /* SNAPSHOT_REMOVE */
|
|
||||||
|
|
||||||
static void _umount(const char *device, int major, int minor)
|
static void _umount(const char *device, int major, int minor)
|
||||||
{
|
{
|
||||||
FILE *mounts;
|
FILE *mounts;
|
||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
char *words[3];
|
char *words[3];
|
||||||
struct stat st;
|
struct stat st;
|
||||||
const char procmounts[] = "/proc/mounts";
|
|
||||||
|
|
||||||
if (!(mounts = fopen(procmounts, "r"))) {
|
if (!(mounts = fopen("/proc/mounts", "r"))) {
|
||||||
log_sys_error("fopen", procmounts);
|
syslog(LOG_ERR, "Could not read /proc/mounts. Not umounting %s.\n", device);
|
||||||
log_error("Not umounting %s.", device);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,24 +110,23 @@ static void _umount(const char *device, int major, int minor)
|
|||||||
continue; /* can't stat, skip this one */
|
continue; /* can't stat, skip this one */
|
||||||
|
|
||||||
if (S_ISBLK(st.st_mode) &&
|
if (S_ISBLK(st.st_mode) &&
|
||||||
(int) major(st.st_rdev) == major &&
|
major(st.st_rdev) == major &&
|
||||||
(int) minor(st.st_rdev) == minor) {
|
minor(st.st_rdev) == minor) {
|
||||||
log_error("Unmounting invalid snapshot %s from %s.", device, words[1]);
|
syslog(LOG_ERR, "Unmounting invalid snapshot %s from %s.\n", device, words[1]);
|
||||||
if (!_run(UMOUNT_COMMAND, "-fl", words[1], NULL))
|
if (!_run(UMOUNT_COMMAND, "-fl", words[1], NULL))
|
||||||
log_error("Failed to umount snapshot %s from %s: %s.",
|
syslog(LOG_ERR, "Failed to umount snapshot %s from %s: %s.\n",
|
||||||
device, words[1], strerror(errno));
|
device, words[1], strerror(errno));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fclose(mounts))
|
if (fclose(mounts))
|
||||||
log_sys_error("close", procmounts);
|
syslog(LOG_ERR, "Failed to close /proc/mounts.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_event(struct dm_task *dmt,
|
void process_event(struct dm_task *dmt,
|
||||||
enum dm_event_mask event __attribute__((unused)),
|
enum dm_event_mask event __attribute__((unused)),
|
||||||
void **user)
|
void **private)
|
||||||
{
|
{
|
||||||
struct dso_state *state = *user;
|
|
||||||
void *next = NULL;
|
void *next = NULL;
|
||||||
uint64_t start, length;
|
uint64_t start, length;
|
||||||
char *target_type = NULL;
|
char *target_type = NULL;
|
||||||
@@ -173,47 +134,28 @@ void process_event(struct dm_task *dmt,
|
|||||||
struct dm_status_snapshot *status = NULL;
|
struct dm_status_snapshot *status = NULL;
|
||||||
const char *device = dm_task_get_name(dmt);
|
const char *device = dm_task_get_name(dmt);
|
||||||
int percent;
|
int percent;
|
||||||
struct dm_info info;
|
struct dso_state *state = *private;
|
||||||
|
|
||||||
/* No longer monitoring, waiting for remove */
|
/* No longer monitoring, waiting for remove */
|
||||||
if (!state->percent_check)
|
if (!state->percent_check)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
dmeventd_lvm2_lock();
|
||||||
|
|
||||||
dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
||||||
if (!target_type || strcmp(target_type, "snapshot")) {
|
if (!target_type)
|
||||||
log_error("Target %s is not snapshot.", target_type);
|
goto out;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dm_get_status_snapshot(state->mem, params, &status)) {
|
if (!dm_get_status_snapshot(state->mem, params, &status))
|
||||||
log_error("Cannot parse snapshot %s state: %s.", device, params);
|
goto out;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
if (status->invalid) {
|
||||||
* If the snapshot has been invalidated or we failed to parse
|
struct dm_info info;
|
||||||
* the status string. Report the full status string to syslog.
|
if (dm_task_get_info(dmt, &info)) {
|
||||||
*/
|
dmeventd_lvm2_unlock();
|
||||||
if (status->invalid || status->overflow || !status->total_sectors) {
|
|
||||||
log_warn("WARNING: Snapshot %s changed state to: %s and should be removed.",
|
|
||||||
device, params);
|
|
||||||
state->percent_check = 0;
|
|
||||||
if (dm_task_get_info(dmt, &info))
|
|
||||||
_umount(device, info.major, info.minor);
|
_umount(device, info.major, info.minor);
|
||||||
#ifdef SNAPSHOT_REMOVE
|
return;
|
||||||
/* Maybe configurable ? */
|
} /* else; too bad, but this is best-effort thing... */
|
||||||
_remove(dm_task_get_uuid(dmt));
|
|
||||||
#endif
|
|
||||||
pthread_kill(pthread_self(), SIGALRM);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (length <= (status->used_sectors - status->metadata_sectors)) {
|
|
||||||
/* TODO eventually recognize earlier when room is enough */
|
|
||||||
log_info("Dropping monitoring of fully provisioned snapshot %s.",
|
|
||||||
device);
|
|
||||||
pthread_kill(pthread_self(), SIGALRM);
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Snapshot size had changed. Clear the threshold. */
|
/* Snapshot size had changed. Clear the threshold. */
|
||||||
@@ -222,50 +164,69 @@ void process_event(struct dm_task *dmt,
|
|||||||
state->known_size = status->total_sectors;
|
state->known_size = status->total_sectors;
|
||||||
}
|
}
|
||||||
|
|
||||||
percent = dm_make_percent(status->used_sectors, status->total_sectors);
|
/*
|
||||||
|
* If the snapshot has been invalidated or we failed to parse
|
||||||
|
* the status string. Report the full status string to syslog.
|
||||||
|
*/
|
||||||
|
if (status->invalid || !status->total_sectors) {
|
||||||
|
syslog(LOG_ERR, "Snapshot %s changed state to: %s\n", device, params);
|
||||||
|
state->percent_check = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
percent = (int) (100 * status->used_sectors / status->total_sectors);
|
||||||
if (percent >= state->percent_check) {
|
if (percent >= state->percent_check) {
|
||||||
/* Usage has raised more than CHECK_STEP since the last
|
/* Usage has raised more than CHECK_STEP since the last
|
||||||
time. Run actions. */
|
time. Run actions. */
|
||||||
state->percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
|
state->percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
|
||||||
|
|
||||||
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
|
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
|
||||||
log_warn("WARNING: Snapshot %s is now %.2f%% full.",
|
syslog(LOG_WARNING, "Snapshot %s is now %i%% full.\n", device, percent);
|
||||||
device, dm_percent_to_float(percent));
|
|
||||||
|
|
||||||
/* Try to extend the snapshot, in accord with user-set policies */
|
/* Try to extend the snapshot, in accord with user-set policies */
|
||||||
if (!_extend(state->cmd_lvextend))
|
if (!_extend(state->cmd_str))
|
||||||
log_error("Failed to extend snapshot %s.", device);
|
syslog(LOG_ERR, "Failed to extend snapshot %s.\n", device);
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
dm_pool_free(state->mem, status);
|
if (status)
|
||||||
|
dm_pool_free(state->mem, status);
|
||||||
|
dmeventd_lvm2_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
int register_device(const char *device,
|
int register_device(const char *device,
|
||||||
const char *uuid __attribute__((unused)),
|
const char *uuid __attribute__((unused)),
|
||||||
int major __attribute__((unused)),
|
int major __attribute__((unused)),
|
||||||
int minor __attribute__((unused)),
|
int minor __attribute__((unused)),
|
||||||
void **user)
|
void **private)
|
||||||
{
|
{
|
||||||
|
struct dm_pool *statemem = NULL;
|
||||||
struct dso_state *state;
|
struct dso_state *state;
|
||||||
|
|
||||||
if (!dmeventd_lvm2_init_with_pool("snapshot_state", state))
|
if (!dmeventd_lvm2_init())
|
||||||
goto_bad;
|
goto out;
|
||||||
|
|
||||||
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvextend,
|
if (!(statemem = dm_pool_create("snapshot_state", 512)) ||
|
||||||
sizeof(state->cmd_lvextend),
|
!(state = dm_pool_zalloc(statemem, sizeof(*state))))
|
||||||
"lvextend --use-policies", device)) {
|
goto bad;
|
||||||
dmeventd_lvm2_exit_with_pool(state);
|
|
||||||
goto_bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (!dmeventd_lvm2_command(statemem, state->cmd_str,
|
||||||
|
sizeof(state->cmd_str),
|
||||||
|
"lvextend --use-policies", device))
|
||||||
|
goto bad;
|
||||||
|
|
||||||
|
state->mem = statemem;
|
||||||
state->percent_check = CHECK_MINIMUM;
|
state->percent_check = CHECK_MINIMUM;
|
||||||
*user = state;
|
*private = state;
|
||||||
|
|
||||||
log_info("Monitoring snapshot %s.", device);
|
syslog(LOG_INFO, "Monitoring snapshot %s\n", device);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
bad:
|
bad:
|
||||||
log_error("Failed to monitor snapshot %s.", device);
|
if (statemem)
|
||||||
|
dm_pool_destroy(statemem);
|
||||||
|
dmeventd_lvm2_exit();
|
||||||
|
out:
|
||||||
|
syslog(LOG_ERR, "Failed to monitor snapshot %s.\n", device);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -274,12 +235,13 @@ int unregister_device(const char *device,
|
|||||||
const char *uuid __attribute__((unused)),
|
const char *uuid __attribute__((unused)),
|
||||||
int major __attribute__((unused)),
|
int major __attribute__((unused)),
|
||||||
int minor __attribute__((unused)),
|
int minor __attribute__((unused)),
|
||||||
void **user)
|
void **private)
|
||||||
{
|
{
|
||||||
struct dso_state *state = *user;
|
struct dso_state *state = *private;
|
||||||
|
|
||||||
dmeventd_lvm2_exit_with_pool(state);
|
syslog(LOG_INFO, "No longer monitoring snapshot %s\n", device);
|
||||||
log_info("No longer monitoring snapshot %s.", device);
|
dm_pool_destroy(state->mem);
|
||||||
|
dmeventd_lvm2_exit();
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program; if not, write to the Free Software Foundation,
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
srcdir = @srcdir@
|
srcdir = @srcdir@
|
||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2011-2016 Red Hat, Inc. All rights reserved.
|
* Copyright (C) 2011-2013 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is part of LVM2.
|
* This file is part of LVM2.
|
||||||
*
|
*
|
||||||
@@ -9,39 +9,28 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* 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,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lib.h" /* using here lvm log */
|
#include "lib.h"
|
||||||
#include "dmeventd_lvm.h"
|
|
||||||
#include "libdevmapper-event.h"
|
#include "libdevmapper-event.h"
|
||||||
|
#include "dmeventd_lvm.h"
|
||||||
|
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
#include <syslog.h> /* FIXME Replace syslog with multilog */
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <pthread.h>
|
/* FIXME Missing openlog? */
|
||||||
|
|
||||||
/* TODO - move this mountinfo code into library to be reusable */
|
/* First warning when thin is 80% full. */
|
||||||
#ifdef __linux__
|
#define WARNING_THRESH 80
|
||||||
# include "kdev_t.h"
|
|
||||||
#else
|
|
||||||
# define MAJOR(x) major((x))
|
|
||||||
# define MINOR(x) minor((x))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* 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%. */
|
/* Run a check every 5%. */
|
||||||
#define CHECK_STEP (DM_PERCENT_1 * 5)
|
#define CHECK_STEP 5
|
||||||
/* Do not bother checking thin data or metadata is less than 50% full. */
|
/* Do not bother checking thins less than 50% full. */
|
||||||
#define CHECK_MINIMUM (DM_PERCENT_1 * 50)
|
#define CHECK_MINIMUM 50
|
||||||
|
|
||||||
#define UMOUNT_COMMAND "/bin/umount"
|
#define UMOUNT_COMMAND "/bin/umount"
|
||||||
|
|
||||||
#define MAX_FAILS (10)
|
|
||||||
|
|
||||||
#define THIN_DEBUG 0
|
#define THIN_DEBUG 0
|
||||||
|
|
||||||
struct dso_state {
|
struct dso_state {
|
||||||
@@ -50,58 +39,18 @@ struct dso_state {
|
|||||||
int data_percent_check;
|
int data_percent_check;
|
||||||
uint64_t known_metadata_size;
|
uint64_t known_metadata_size;
|
||||||
uint64_t known_data_size;
|
uint64_t known_data_size;
|
||||||
unsigned fails;
|
|
||||||
char cmd_str[1024];
|
char cmd_str[1024];
|
||||||
};
|
};
|
||||||
|
|
||||||
DM_EVENT_LOG_FN("thin")
|
|
||||||
|
|
||||||
#define UUID_PREFIX "LVM-"
|
/* TODO - move this mountinfo code into library to be reusable */
|
||||||
|
#ifdef __linux__
|
||||||
/* Figure out device UUID has LVM- prefix and is OPEN */
|
# include "kdev_t.h"
|
||||||
static int _has_unmountable_prefix(int major, int minor)
|
#else
|
||||||
{
|
# define MAJOR(x) major((x))
|
||||||
struct dm_task *dmt;
|
# define MINOR(x) minor((x))
|
||||||
struct dm_info info;
|
# define MKDEV(x,y) makedev((x),(y))
|
||||||
const char *uuid;
|
|
||||||
int r = 0;
|
|
||||||
|
|
||||||
if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
|
|
||||||
return_0;
|
|
||||||
|
|
||||||
if (!dm_task_set_major_minor(dmt, major, minor, 1))
|
|
||||||
goto_out;
|
|
||||||
|
|
||||||
if (!dm_task_no_flush(dmt))
|
|
||||||
stack;
|
|
||||||
|
|
||||||
if (!dm_task_run(dmt))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (!dm_task_get_info(dmt, &info))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (!info.exists || !info.open_count)
|
|
||||||
goto out; /* Not open -> not mounted */
|
|
||||||
|
|
||||||
if (!(uuid = dm_task_get_uuid(dmt)))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/* Check it's public mountable LV
|
|
||||||
* has prefix LVM- and UUID size is 68 chars */
|
|
||||||
if (memcmp(uuid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1) ||
|
|
||||||
strlen(uuid) != 68)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
#if THIN_DEBUG
|
|
||||||
log_debug("Found logical volume %s (%u:%u).", uuid, major, minor);
|
|
||||||
#endif
|
#endif
|
||||||
r = 1;
|
|
||||||
out:
|
|
||||||
dm_task_destroy(dmt);
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get dependencies for device, and try to find matching device */
|
/* 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)
|
static int _has_deps(const char *name, int tp_major, int tp_minor, int *dev_minor)
|
||||||
@@ -140,15 +89,12 @@ static int _has_deps(const char *name, int tp_major, int tp_minor, int *dev_mino
|
|||||||
|
|
||||||
*dev_minor = info.minor;
|
*dev_minor = info.minor;
|
||||||
|
|
||||||
if (!_has_unmountable_prefix(major, info.minor))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
#if THIN_DEBUG
|
#if THIN_DEBUG
|
||||||
{
|
{
|
||||||
char dev_name[PATH_MAX];
|
char dev_name[PATH_MAX];
|
||||||
if (dm_device_get_name(major, minor, 0, dev_name, sizeof(dev_name)))
|
if (dm_device_get_name(major, minor, 0, dev_name, sizeof(dev_name)))
|
||||||
log_debug("Found %s (%u:%u) depends on %s.",
|
syslog(LOG_DEBUG, "Found %s (%u:%u) depends on %s",
|
||||||
name, major, *dev_minor, dev_name);
|
name, major, *dev_minor, dev_name);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
r = 1;
|
r = 1;
|
||||||
@@ -195,6 +141,14 @@ out:
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _extend(struct dso_state *state)
|
||||||
|
{
|
||||||
|
#if THIN_DEBUG
|
||||||
|
syslog(LOG_INFO, "dmeventd executes: %s.\n", state->cmd_str);
|
||||||
|
#endif
|
||||||
|
return dmeventd_lvm2_run(state->cmd_str);
|
||||||
|
}
|
||||||
|
|
||||||
static int _run(const char *cmd, ...)
|
static int _run(const char *cmd, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
@@ -214,12 +168,12 @@ static int _run(const char *cmd, ...)
|
|||||||
argv = alloca(sizeof(const char *) * (argc + 1));
|
argv = alloca(sizeof(const char *) * (argc + 1));
|
||||||
|
|
||||||
argv[0] = cmd;
|
argv[0] = cmd;
|
||||||
va_start(ap, cmd);
|
va_start(ap, cmd);
|
||||||
while ((argv[++i] = va_arg(ap, const char *)));
|
while ((argv[++i] = va_arg(ap, const char *)));
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
execvp(cmd, (char **)argv);
|
execvp(cmd, (char **)argv);
|
||||||
log_sys_error("exec", cmd);
|
syslog(LOG_ERR, "Failed to execute %s: %s.\n", cmd, strerror(errno));
|
||||||
exit(127);
|
exit(127);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,135 +191,103 @@ static int _run(const char *cmd, ...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct mountinfo_s {
|
struct mountinfo_s {
|
||||||
const char *device;
|
|
||||||
struct dm_info info;
|
struct dm_info info;
|
||||||
dm_bitset_t minors; /* Bitset for active thin pool minors */
|
dm_bitset_t minors; /* Bitset for active thin pool minors */
|
||||||
|
const char *device;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int _umount_device(char *buffer, unsigned major, unsigned minor,
|
static int _umount_device(char *buffer, unsigned major, unsigned minor,
|
||||||
char *target, void *cb_data)
|
char *target, void *cb_data)
|
||||||
{
|
{
|
||||||
struct mountinfo_s *data = cb_data;
|
struct mountinfo_s *data = cb_data;
|
||||||
char *words[10];
|
|
||||||
|
|
||||||
if ((major == data->info.major) && dm_bit(data->minors, minor)) {
|
if ((major == data->info.major) && dm_bit(data->minors, minor)) {
|
||||||
if (dm_split_words(buffer, DM_ARRAY_SIZE(words), 0, words) < DM_ARRAY_SIZE(words))
|
syslog(LOG_INFO, "Unmounting thin volume %s from %s.\n",
|
||||||
words[9] = NULL; /* just don't show device name */
|
data->device, target);
|
||||||
log_info("Unmounting thin %s (%d:%d) of thin-pool %s (%u:%u) from mount point \"%s\".",
|
|
||||||
words[9] ? : "", major, minor, data->device,
|
|
||||||
data->info.major, data->info.minor,
|
|
||||||
target);
|
|
||||||
if (!_run(UMOUNT_COMMAND, "-fl", target, NULL))
|
if (!_run(UMOUNT_COMMAND, "-fl", target, NULL))
|
||||||
log_error("Failed to lazy umount thin %s (%d:%d) from %s: %s.",
|
syslog(LOG_ERR, "Failed to umount thin %s from %s: %s.\n",
|
||||||
words[9], major, minor, target, strerror(errno));
|
data->device, target, strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find all thin pool LV users and try to umount them.
|
* Find all thin pool users and try to umount them.
|
||||||
* TODO: work with read-only thin pool support
|
* TODO: work with read-only thin pool support
|
||||||
*/
|
*/
|
||||||
static void _umount(struct dm_task *dmt)
|
static void _umount(struct dm_task *dmt, const char *device)
|
||||||
{
|
{
|
||||||
/* TODO: Convert to use hash to reduce memory usage */
|
/* TODO: Convert to use hash to reduce memory usage */
|
||||||
static const size_t MINORS = (1U << 20); /* 20 bit */
|
static const size_t MINORS = (1U << 20); /* 20 bit */
|
||||||
struct mountinfo_s data = { NULL };
|
struct mountinfo_s data = {
|
||||||
|
.device = device,
|
||||||
|
};
|
||||||
|
|
||||||
if (!dm_task_get_info(dmt, &data.info))
|
if (!dm_task_get_info(dmt, &data.info))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
data.device = dm_task_get_name(dmt);
|
dmeventd_lvm2_unlock();
|
||||||
|
|
||||||
if (!(data.minors = dm_bitset_create(NULL, MINORS))) {
|
if (!(data.minors = dm_bitset_create(NULL, MINORS))) {
|
||||||
log_error("Failed to allocate bitset. Not unmounting %s.", data.device);
|
syslog(LOG_ERR, "Failed to allocate bitset. Not unmounting %s.\n", device);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_find_all_devs(data.minors, data.info.major, data.info.minor)) {
|
if (!_find_all_devs(data.minors, data.info.major, data.info.minor)) {
|
||||||
log_error("Failed to detect mounted volumes for %s.", data.device);
|
syslog(LOG_ERR, "Failed to detect mounted volumes for %s.\n", device);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dm_mountinfo_read(_umount_device, &data)) {
|
if (!dm_mountinfo_read(_umount_device, &data)) {
|
||||||
log_error("Could not parse mountinfo file.");
|
syslog(LOG_ERR, "Could not parse mountinfo file.\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (data.minors)
|
if (data.minors)
|
||||||
dm_bitset_destroy(data.minors);
|
dm_bitset_destroy(data.minors);
|
||||||
}
|
dmeventd_lvm2_lock();
|
||||||
|
|
||||||
static int _use_policy(struct dm_task *dmt, struct dso_state *state)
|
|
||||||
{
|
|
||||||
#if THIN_DEBUG
|
|
||||||
log_info("dmeventd executes: %s.", state->cmd_str);
|
|
||||||
#endif
|
|
||||||
if (!dmeventd_lvm2_run_with_lock(state->cmd_str)) {
|
|
||||||
log_error("Failed to extend thin pool %s.",
|
|
||||||
dm_task_get_name(dmt));
|
|
||||||
state->fails++;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
state->fails = 0;
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_event(struct dm_task *dmt,
|
void process_event(struct dm_task *dmt,
|
||||||
enum dm_event_mask event __attribute__((unused)),
|
enum dm_event_mask event __attribute__((unused)),
|
||||||
void **user)
|
void **private)
|
||||||
{
|
{
|
||||||
const char *device = dm_task_get_name(dmt);
|
const char *device = dm_task_get_name(dmt);
|
||||||
int percent;
|
int percent;
|
||||||
struct dso_state *state = *user;
|
struct dso_state *state = *private;
|
||||||
struct dm_status_thin_pool *tps = NULL;
|
struct dm_status_thin_pool *tps = NULL;
|
||||||
void *next = NULL;
|
void *next = NULL;
|
||||||
uint64_t start, length;
|
uint64_t start, length;
|
||||||
char *target_type = NULL;
|
char *target_type = NULL;
|
||||||
char *params;
|
char *params;
|
||||||
int needs_policy = 0;
|
|
||||||
int needs_umount = 0;
|
|
||||||
|
|
||||||
#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 0
|
#if 0
|
||||||
/* No longer monitoring, waiting for remove */
|
/* No longer monitoring, waiting for remove */
|
||||||
if (!state->meta_percent_check && !state->data_percent_check)
|
if (!state->meta_percent_check && !state->data_percent_check)
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
if (event & DM_EVENT_DEVICE_ERROR) {
|
dmeventd_lvm2_lock();
|
||||||
/* Error -> no need to check and do instant resize */
|
|
||||||
if (_use_policy(dmt, state))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
stack;
|
|
||||||
}
|
|
||||||
|
|
||||||
dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
||||||
|
|
||||||
if (!target_type || (strcmp(target_type, "thin-pool") != 0)) {
|
if (!target_type || (strcmp(target_type, "thin-pool") != 0)) {
|
||||||
log_error("Invalid target type.");
|
syslog(LOG_ERR, "Invalid target type.\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dm_get_status_thin_pool(state->mem, params, &tps)) {
|
if (!dm_get_status_thin_pool(state->mem, params, &tps)) {
|
||||||
log_error("Failed to parse status.");
|
syslog(LOG_ERR, "Failed to parse status.\n");
|
||||||
needs_umount = 1;
|
_umount(dmt, device);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if THIN_DEBUG
|
#if THIN_DEBUG
|
||||||
log_debug("Thin pool status " FMTu64 "/" FMTu64 " "
|
syslog(LOG_INFO, "%p: Got status %" PRIu64 " / %" PRIu64
|
||||||
FMTu64 "/" FMTu64 ".",
|
" %" PRIu64 " / %" PRIu64 ".\n", state,
|
||||||
tps->used_metadata_blocks, tps->total_metadata_blocks,
|
tps->used_metadata_blocks, tps->total_metadata_blocks,
|
||||||
tps->used_data_blocks, tps->total_data_blocks);
|
tps->used_data_blocks, tps->total_data_blocks);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Thin pool size had changed. Clear the threshold. */
|
/* Thin pool size had changed. Clear the threshold. */
|
||||||
@@ -379,7 +301,7 @@ void process_event(struct dm_task *dmt,
|
|||||||
state->known_data_size = tps->total_data_blocks;
|
state->known_data_size = tps->total_data_blocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
percent = dm_make_percent(tps->used_metadata_blocks, tps->total_metadata_blocks);
|
percent = 100 * tps->used_metadata_blocks / tps->total_metadata_blocks;
|
||||||
if (percent >= state->metadata_percent_check) {
|
if (percent >= state->metadata_percent_check) {
|
||||||
/*
|
/*
|
||||||
* Usage has raised more than CHECK_STEP since the last
|
* Usage has raised more than CHECK_STEP since the last
|
||||||
@@ -389,15 +311,18 @@ void process_event(struct dm_task *dmt,
|
|||||||
|
|
||||||
/* FIXME: extension of metadata needs to be written! */
|
/* FIXME: extension of metadata needs to be written! */
|
||||||
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
|
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
|
||||||
log_warn("WARNING: Thin pool %s metadata is now %.2f%% full.",
|
syslog(LOG_WARNING, "Thin metadata %s is now %i%% full.\n",
|
||||||
device, dm_percent_to_float(percent));
|
device, percent);
|
||||||
needs_policy = 1;
|
/* Try to extend the metadata, in accord with user-set policies */
|
||||||
|
if (!_extend(state)) {
|
||||||
if (percent >= UMOUNT_THRESH)
|
syslog(LOG_ERR, "Failed to extend thin metadata %s.\n",
|
||||||
needs_umount = 1;
|
device);
|
||||||
|
_umount(dmt, device);
|
||||||
|
}
|
||||||
|
/* FIXME: hmm READ-ONLY switch should happen in error path */
|
||||||
}
|
}
|
||||||
|
|
||||||
percent = dm_make_percent(tps->used_data_blocks, tps->total_data_blocks);
|
percent = 100 * tps->used_data_blocks / tps->total_data_blocks;
|
||||||
if (percent >= state->data_percent_check) {
|
if (percent >= state->data_percent_check) {
|
||||||
/*
|
/*
|
||||||
* Usage has raised more than CHECK_STEP since
|
* Usage has raised more than CHECK_STEP since
|
||||||
@@ -406,63 +331,56 @@ void process_event(struct dm_task *dmt,
|
|||||||
state->data_percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
|
state->data_percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
|
||||||
|
|
||||||
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
|
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
|
||||||
log_warn("WARNING: Thin pool %s data is now %.2f%% full.",
|
syslog(LOG_WARNING, "Thin %s is now %i%% full.\n", device, percent);
|
||||||
device, dm_percent_to_float(percent));
|
/* Try to extend the thin data, in accord with user-set policies */
|
||||||
needs_policy = 1;
|
if (!_extend(state)) {
|
||||||
|
syslog(LOG_ERR, "Failed to extend thin %s.\n", device);
|
||||||
if (percent >= UMOUNT_THRESH)
|
state->data_percent_check = 0;
|
||||||
needs_umount = 1;
|
_umount(dmt, device);
|
||||||
|
}
|
||||||
|
/* FIXME: hmm READ-ONLY switch should happen in error path */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needs_policy &&
|
|
||||||
_use_policy(dmt, state))
|
|
||||||
needs_umount = 0; /* No umount when command was successful */
|
|
||||||
out:
|
out:
|
||||||
if (needs_umount) {
|
|
||||||
_umount(dmt);
|
|
||||||
/* Until something changes, do not retry any more actions */
|
|
||||||
state->data_percent_check = state->metadata_percent_check = (DM_PERCENT_1 * 101);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tps)
|
if (tps)
|
||||||
dm_pool_free(state->mem, tps);
|
dm_pool_free(state->mem, tps);
|
||||||
|
|
||||||
if (state->fails >= MAX_FAILS) {
|
dmeventd_lvm2_unlock();
|
||||||
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,
|
int register_device(const char *device,
|
||||||
const char *uuid __attribute__((unused)),
|
const char *uuid __attribute__((unused)),
|
||||||
int major __attribute__((unused)),
|
int major __attribute__((unused)),
|
||||||
int minor __attribute__((unused)),
|
int minor __attribute__((unused)),
|
||||||
void **user)
|
void **private)
|
||||||
{
|
{
|
||||||
|
struct dm_pool *statemem = NULL;
|
||||||
struct dso_state *state;
|
struct dso_state *state;
|
||||||
|
|
||||||
if (!dmeventd_lvm2_init_with_pool("thin_pool_state", state))
|
if (!dmeventd_lvm2_init())
|
||||||
goto_bad;
|
goto bad;
|
||||||
|
|
||||||
if (!dmeventd_lvm2_command(state->mem, state->cmd_str,
|
if (!(statemem = dm_pool_create("thin_pool_state", 2048)) ||
|
||||||
|
!(state = dm_pool_zalloc(statemem, sizeof(*state))) ||
|
||||||
|
!dmeventd_lvm2_command(statemem, state->cmd_str,
|
||||||
sizeof(state->cmd_str),
|
sizeof(state->cmd_str),
|
||||||
"lvextend --use-policies",
|
"lvextend --use-policies",
|
||||||
device)) {
|
device)) {
|
||||||
dmeventd_lvm2_exit_with_pool(state);
|
if (statemem)
|
||||||
goto_bad;
|
dm_pool_destroy(statemem);
|
||||||
|
dmeventd_lvm2_exit();
|
||||||
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state->mem = statemem;
|
||||||
state->metadata_percent_check = CHECK_MINIMUM;
|
state->metadata_percent_check = CHECK_MINIMUM;
|
||||||
state->data_percent_check = CHECK_MINIMUM;
|
state->data_percent_check = CHECK_MINIMUM;
|
||||||
*user = state;
|
*private = state;
|
||||||
|
|
||||||
log_info("Monitoring thin %s.", device);
|
syslog(LOG_INFO, "Monitoring thin %s.\n", device);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
bad:
|
bad:
|
||||||
log_error("Failed to monitor thin %s.", device);
|
syslog(LOG_ERR, "Failed to monitor thin %s.\n", device);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -471,12 +389,13 @@ int unregister_device(const char *device,
|
|||||||
const char *uuid __attribute__((unused)),
|
const char *uuid __attribute__((unused)),
|
||||||
int major __attribute__((unused)),
|
int major __attribute__((unused)),
|
||||||
int minor __attribute__((unused)),
|
int minor __attribute__((unused)),
|
||||||
void **user)
|
void **private)
|
||||||
{
|
{
|
||||||
struct dso_state *state = *user;
|
struct dso_state *state = *private;
|
||||||
|
|
||||||
dmeventd_lvm2_exit_with_pool(state);
|
syslog(LOG_INFO, "No longer monitoring thin %s.\n", device);
|
||||||
log_info("No longer monitoring thin %s.", device);
|
dm_pool_destroy(state->mem);
|
||||||
|
dmeventd_lvm2_exit();
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (C) 2016 Red Hat, Inc. All rights reserved.
|
|
||||||
#
|
|
||||||
# This file is part of LVM2.
|
|
||||||
#
|
|
||||||
# This copyrighted material is made available to anyone wishing to use,
|
|
||||||
# modify, copy, or redistribute it subject to the terms and conditions
|
|
||||||
# of the GNU General Public License v.2.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU 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
|
|
||||||
|
|
||||||
srcdir = @srcdir@
|
|
||||||
top_srcdir = @top_srcdir@
|
|
||||||
top_builddir = @top_builddir@
|
|
||||||
|
|
||||||
lvmdbusdir = $(python3dir)/lvmdbusd
|
|
||||||
|
|
||||||
LVMDBUS_SRCDIR_FILES = \
|
|
||||||
automatedproperties.py \
|
|
||||||
background.py \
|
|
||||||
cfg.py \
|
|
||||||
cmdhandler.py \
|
|
||||||
fetch.py \
|
|
||||||
__init__.py \
|
|
||||||
job.py \
|
|
||||||
loader.py \
|
|
||||||
lvmdb.py \
|
|
||||||
main.py \
|
|
||||||
lvm_shell_proxy.py \
|
|
||||||
lv.py \
|
|
||||||
manager.py \
|
|
||||||
objectmanager.py \
|
|
||||||
pv.py \
|
|
||||||
refresh.py \
|
|
||||||
request.py \
|
|
||||||
state.py \
|
|
||||||
udevwatch.py \
|
|
||||||
utils.py \
|
|
||||||
vg.py
|
|
||||||
|
|
||||||
LVMDBUS_BUILDDIR_FILES = \
|
|
||||||
path.py
|
|
||||||
|
|
||||||
LVMDBUSD = $(srcdir)/lvmdbusd
|
|
||||||
|
|
||||||
include $(top_builddir)/make.tmpl
|
|
||||||
|
|
||||||
.PHONY: install_lvmdbusd
|
|
||||||
|
|
||||||
install_lvmdbusd:
|
|
||||||
$(INSTALL_DIR) $(sbindir)
|
|
||||||
$(INSTALL_SCRIPT) $(LVMDBUSD) $(sbindir)
|
|
||||||
$(INSTALL_DIR) $(DESTDIR)$(lvmdbusdir)
|
|
||||||
(cd $(srcdir); $(INSTALL_DATA) $(LVMDBUS_SRCDIR_FILES) $(DESTDIR)$(lvmdbusdir))
|
|
||||||
$(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]
|
|
||||||
|
|
||||||
install_lvm2: install_lvmdbusd
|
|
||||||
|
|
||||||
install: install_lvm2
|
|
||||||
|
|
||||||
DISTCLEAN_TARGETS+= \
|
|
||||||
$(LVMDBUS_BUILDDIR_FILES)
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
# 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/>.
|
|
||||||
|
|
||||||
from .main import main
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
# 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/>.
|
|
||||||
|
|
||||||
import dbus
|
|
||||||
from . import cfg
|
|
||||||
from .utils import get_properties, add_properties, get_object_property_diff, \
|
|
||||||
log_debug
|
|
||||||
from .state import State
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyPep8Naming,PyUnresolvedReferences
|
|
||||||
class AutomatedProperties(dbus.service.Object):
|
|
||||||
"""
|
|
||||||
This class implements the needed interfaces for:
|
|
||||||
org.freedesktop.DBus.Properties
|
|
||||||
|
|
||||||
Other classes inherit from it to get the same behavior
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, object_path, search_method=None):
|
|
||||||
dbus.service.Object.__init__(self, cfg.bus, object_path)
|
|
||||||
self._ap_interface = []
|
|
||||||
self._ap_o_path = object_path
|
|
||||||
self._ap_search_method = search_method
|
|
||||||
self.state = None
|
|
||||||
|
|
||||||
def dbus_object_path(self):
|
|
||||||
return self._ap_o_path
|
|
||||||
|
|
||||||
def emit_data(self):
|
|
||||||
props = {}
|
|
||||||
|
|
||||||
for i in self.interface():
|
|
||||||
props[i] = self.GetAll(i)
|
|
||||||
|
|
||||||
return self._ap_o_path, props
|
|
||||||
|
|
||||||
def set_interface(self, interface):
|
|
||||||
"""
|
|
||||||
With inheritance we can't easily tell what interfaces a class provides
|
|
||||||
so we will have each class that implements an interface tell the
|
|
||||||
base AutomatedProperties what it is they do provide. This is kind of
|
|
||||||
clunky and perhaps we can figure out a better way to do this later.
|
|
||||||
:param interface: An interface the object supports
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if interface not in self._ap_interface:
|
|
||||||
self._ap_interface.append(interface)
|
|
||||||
|
|
||||||
# noinspection PyUnusedLocal
|
|
||||||
def interface(self, all_interfaces=False):
|
|
||||||
if all_interfaces:
|
|
||||||
cpy = list(self._ap_interface)
|
|
||||||
cpy.extend(
|
|
||||||
["org.freedesktop.DBus.Introspectable",
|
|
||||||
"org.freedesktop.DBus.Properties"])
|
|
||||||
return cpy
|
|
||||||
|
|
||||||
return self._ap_interface
|
|
||||||
|
|
||||||
# Properties
|
|
||||||
# noinspection PyUnusedLocal
|
|
||||||
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
|
|
||||||
in_signature='ss', out_signature='v')
|
|
||||||
def Get(self, interface_name, property_name):
|
|
||||||
value = getattr(self, property_name)
|
|
||||||
# Note: If we get an exception in this handler we won't know about it,
|
|
||||||
# only the side effect of no returned value!
|
|
||||||
log_debug('Get (%s), type (%s), value(%s)' %
|
|
||||||
(property_name, str(type(value)), str(value)))
|
|
||||||
return value
|
|
||||||
|
|
||||||
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
|
|
||||||
in_signature='s', out_signature='a{sv}')
|
|
||||||
def GetAll(self, interface_name):
|
|
||||||
if interface_name in self.interface(True):
|
|
||||||
# Using introspection, lets build this dynamically
|
|
||||||
properties = get_properties(self)
|
|
||||||
if interface_name in properties:
|
|
||||||
return properties[interface_name][1]
|
|
||||||
return {}
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
self._ap_interface,
|
|
||||||
'The object %s does not implement the %s interface'
|
|
||||||
% (self.__class__, interface_name))
|
|
||||||
|
|
||||||
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
|
|
||||||
in_signature='ssv')
|
|
||||||
def Set(self, interface_name, property_name, new_value):
|
|
||||||
setattr(self, property_name, new_value)
|
|
||||||
self.PropertiesChanged(interface_name,
|
|
||||||
{property_name: new_value}, [])
|
|
||||||
|
|
||||||
# As dbus-python does not support introspection for properties we will
|
|
||||||
# get the autogenerated xml and then add our wanted properties to it.
|
|
||||||
@dbus.service.method(dbus_interface=dbus.INTROSPECTABLE_IFACE,
|
|
||||||
out_signature='s')
|
|
||||||
def Introspect(self):
|
|
||||||
r = dbus.service.Object.Introspect(self, self._ap_o_path, cfg.bus)
|
|
||||||
# Look at the properties in the class
|
|
||||||
props = get_properties(self)
|
|
||||||
|
|
||||||
for int_f, v in props.items():
|
|
||||||
r = add_properties(r, int_f, v[0])
|
|
||||||
|
|
||||||
return r
|
|
||||||
|
|
||||||
@dbus.service.signal(dbus_interface=dbus.PROPERTIES_IFACE,
|
|
||||||
signature='sa{sv}as')
|
|
||||||
def PropertiesChanged(self, interface_name, changed_properties,
|
|
||||||
invalidated_properties):
|
|
||||||
log_debug(('SIGNAL: PropertiesChanged(%s, %s, %s, %s)' %
|
|
||||||
(str(self._ap_o_path), str(interface_name),
|
|
||||||
str(changed_properties), str(invalidated_properties))))
|
|
||||||
|
|
||||||
def refresh(self, search_key=None, object_state=None):
|
|
||||||
"""
|
|
||||||
Take the values (properties) of an object and update them with what
|
|
||||||
lvm currently has. You can either fetch the new ones or supply the
|
|
||||||
new state to be updated with
|
|
||||||
:param search_key: The value to use to search for
|
|
||||||
:param object_state: Use this as the new object state
|
|
||||||
"""
|
|
||||||
num_changed = 0
|
|
||||||
|
|
||||||
# If we can't do a lookup, bail now, this happens if we blindly walk
|
|
||||||
# through all dbus objects as some don't have a search method, like
|
|
||||||
# 'Manager' object.
|
|
||||||
if not self._ap_search_method:
|
|
||||||
return
|
|
||||||
|
|
||||||
search = self.lvm_id
|
|
||||||
if search_key:
|
|
||||||
search = search_key
|
|
||||||
|
|
||||||
# Either we have the new object state or we need to go fetch it
|
|
||||||
if object_state:
|
|
||||||
new_state = object_state
|
|
||||||
else:
|
|
||||||
new_state = self._ap_search_method([search])[0]
|
|
||||||
assert isinstance(new_state, State)
|
|
||||||
|
|
||||||
assert new_state
|
|
||||||
|
|
||||||
# When we refresh an object the object identifiers might have changed
|
|
||||||
# because LVM allows the user to change them (name & uuid), thus if
|
|
||||||
# they have changed we need to update the object manager so that
|
|
||||||
# look-ups will happen correctly
|
|
||||||
old_id = self.state.identifiers()
|
|
||||||
new_id = new_state.identifiers()
|
|
||||||
if old_id[0] != new_id[0] or old_id[1] != new_id[1]:
|
|
||||||
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
|
|
||||||
# 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)
|
|
||||||
|
|
||||||
changed = get_object_property_diff(o_prop, n_prop)
|
|
||||||
|
|
||||||
if changed:
|
|
||||||
for int_f, v in changed.items():
|
|
||||||
self.PropertiesChanged(int_f, v, [])
|
|
||||||
num_changed += 1
|
|
||||||
return num_changed
|
|
||||||
@@ -1,173 +0,0 @@
|
|||||||
# 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/>.
|
|
||||||
|
|
||||||
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
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
_rlock = threading.RLock()
|
|
||||||
_thread_list = list()
|
|
||||||
|
|
||||||
|
|
||||||
def pv_move_lv_cmd(move_options, lv_full_name,
|
|
||||||
pv_source, pv_source_range, pv_dest_range_list):
|
|
||||||
cmd = ['pvmove', '-i', '1']
|
|
||||||
cmd.extend(options_to_cli_args(move_options))
|
|
||||||
|
|
||||||
if lv_full_name:
|
|
||||||
cmd.extend(['-n', lv_full_name])
|
|
||||||
|
|
||||||
pv_range_append(cmd, pv_source, *pv_source_range)
|
|
||||||
pv_dest_ranges(cmd, pv_dest_range_list)
|
|
||||||
|
|
||||||
return cmd
|
|
||||||
|
|
||||||
|
|
||||||
def lv_merge_cmd(merge_options, lv_full_name):
|
|
||||||
cmd = ['lvconvert', '--merge', '-i', '1']
|
|
||||||
cmd.extend(options_to_cli_args(merge_options))
|
|
||||||
cmd.append(lv_full_name)
|
|
||||||
return cmd
|
|
||||||
|
|
||||||
|
|
||||||
def _move_merge(interface_name, cmd, job_state):
|
|
||||||
add(cmd, job_state)
|
|
||||||
|
|
||||||
done = job_state.Wait(-1)
|
|
||||||
if not done:
|
|
||||||
ec, err_msg = job_state.GetError
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
interface_name,
|
|
||||||
'Exit code %s, stderr = %s' % (str(ec), err_msg))
|
|
||||||
|
|
||||||
cfg.load()
|
|
||||||
return '/'
|
|
||||||
|
|
||||||
|
|
||||||
def move(interface_name, lv_name, pv_src_obj, pv_source_range,
|
|
||||||
pv_dests_and_ranges, move_options, job_state):
|
|
||||||
"""
|
|
||||||
Common code for the pvmove handling.
|
|
||||||
:param interface_name: What dbus interface we are providing for
|
|
||||||
:param lv_name: Optional (None or name of LV to move)
|
|
||||||
:param pv_src_obj: dbus object patch for source PV
|
|
||||||
: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
|
|
||||||
"""
|
|
||||||
pv_dests = []
|
|
||||||
pv_src = cfg.om.get_object_by_path(pv_src_obj)
|
|
||||||
if pv_src:
|
|
||||||
|
|
||||||
# Check to see if we are handling a move to a specific
|
|
||||||
# destination(s)
|
|
||||||
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(
|
|
||||||
interface_name,
|
|
||||||
'PV Destination (%s) not found' % pr[0])
|
|
||||||
|
|
||||||
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)
|
|
||||||
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):
|
|
||||||
# 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)
|
|
||||||
else:
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
interface_name,
|
|
||||||
'LV with uuid %s and name %s not present!' % (lv_uuid, lv_name))
|
|
||||||
|
|
||||||
|
|
||||||
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 background_execute(command, background_job):
|
|
||||||
|
|
||||||
# Wrap this whole operation in an exception handler, otherwise if we
|
|
||||||
# hit a code bug we will silently exit this thread without anyone being
|
|
||||||
# the wiser.
|
|
||||||
try:
|
|
||||||
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:
|
|
||||||
line_str = line.decode("utf-8")
|
|
||||||
|
|
||||||
# Check to see if the line has the correct number of separators
|
|
||||||
try:
|
|
||||||
if line_str.count(':') == 2:
|
|
||||||
(device, ignore, percentage) = line_str.split(':')
|
|
||||||
background_job.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:
|
|
||||||
background_job.Percent = 100
|
|
||||||
|
|
||||||
background_job.set_result(process.returncode, out[1])
|
|
||||||
|
|
||||||
except Exception:
|
|
||||||
# In the unlikely event that we blow up, we need to unblock caller which
|
|
||||||
# is waiting on an answer.
|
|
||||||
st = traceback.format_exc()
|
|
||||||
error = "Exception in background thread: \n%s" % st
|
|
||||||
log_error(error)
|
|
||||||
background_job.set_result(1, error)
|
|
||||||
|
|
||||||
|
|
||||||
def add(command, reporting_job):
|
|
||||||
# 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))
|
|
||||||
t.start()
|
|
||||||
|
|
||||||
with _rlock:
|
|
||||||
_thread_list.append(t)
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
# 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/>.
|
|
||||||
|
|
||||||
import os
|
|
||||||
import multiprocessing
|
|
||||||
import queue
|
|
||||||
import itertools
|
|
||||||
try:
|
|
||||||
from . import path
|
|
||||||
except SystemError:
|
|
||||||
import path
|
|
||||||
|
|
||||||
LVM_CMD = os.getenv('LVM_BINARY', path.LVM_BINARY)
|
|
||||||
|
|
||||||
# This is the global object manager
|
|
||||||
om = None
|
|
||||||
|
|
||||||
# This is the global bus connection
|
|
||||||
bus = None
|
|
||||||
|
|
||||||
# Shared state variable across all processes
|
|
||||||
run = multiprocessing.Value('i', 1)
|
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
BASE_INTERFACE = 'com.redhat.lvmdbus1'
|
|
||||||
PV_INTERFACE = BASE_INTERFACE + '.Pv'
|
|
||||||
VG_INTERFACE = BASE_INTERFACE + '.Vg'
|
|
||||||
LV_INTERFACE = BASE_INTERFACE + '.Lv'
|
|
||||||
LV_COMMON_INTERFACE = BASE_INTERFACE + '.LvCommon'
|
|
||||||
THIN_POOL_INTERFACE = BASE_INTERFACE + '.ThinPool'
|
|
||||||
CACHE_POOL_INTERFACE = BASE_INTERFACE + '.CachePool'
|
|
||||||
LV_CACHED = BASE_INTERFACE + '.CachedLv'
|
|
||||||
SNAPSHOT_INTERFACE = BASE_INTERFACE + '.Snapshot'
|
|
||||||
MANAGER_INTERFACE = BASE_INTERFACE + '.Manager'
|
|
||||||
JOB_INTERFACE = BASE_INTERFACE + '.Job'
|
|
||||||
|
|
||||||
BASE_OBJ_PATH = '/' + BASE_INTERFACE.replace('.', '/')
|
|
||||||
PV_OBJ_PATH = BASE_OBJ_PATH + '/Pv'
|
|
||||||
VG_OBJ_PATH = BASE_OBJ_PATH + '/Vg'
|
|
||||||
LV_OBJ_PATH = BASE_OBJ_PATH + '/Lv'
|
|
||||||
THIN_POOL_PATH = BASE_OBJ_PATH + "/ThinPool"
|
|
||||||
CACHE_POOL_PATH = BASE_OBJ_PATH + "/CachePool"
|
|
||||||
HIDDEN_LV_PATH = BASE_OBJ_PATH + "/HiddenLv"
|
|
||||||
MANAGER_OBJ_PATH = BASE_OBJ_PATH + '/Manager'
|
|
||||||
JOB_OBJ_PATH = BASE_OBJ_PATH + '/Job'
|
|
||||||
|
|
||||||
# Counters for object path generation
|
|
||||||
pv_id = itertools.count()
|
|
||||||
vg_id = itertools.count()
|
|
||||||
lv_id = itertools.count()
|
|
||||||
thin_id = itertools.count()
|
|
||||||
cache_pool_id = itertools.count()
|
|
||||||
job_id = itertools.count()
|
|
||||||
hidden_lv = itertools.count()
|
|
||||||
|
|
||||||
# Used to prevent circular imports...
|
|
||||||
load = None
|
|
||||||
|
|
||||||
# Global cached state
|
|
||||||
db = None
|
|
||||||
|
|
||||||
# lvm flight recorder
|
|
||||||
blackbox = None
|
|
||||||
@@ -1,724 +0,0 @@
|
|||||||
# 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/>.
|
|
||||||
|
|
||||||
from subprocess import Popen, PIPE
|
|
||||||
import time
|
|
||||||
import threading
|
|
||||||
from itertools import chain
|
|
||||||
import collections
|
|
||||||
|
|
||||||
try:
|
|
||||||
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
|
|
||||||
|
|
||||||
try:
|
|
||||||
import simplejson as json
|
|
||||||
except ImportError:
|
|
||||||
import json
|
|
||||||
|
|
||||||
SEP = '{|}'
|
|
||||||
|
|
||||||
total_time = 0.0
|
|
||||||
total_count = 0
|
|
||||||
|
|
||||||
# We need to prevent different threads from using the same lvm shell
|
|
||||||
# at the same time.
|
|
||||||
cmd_lock = threading.RLock()
|
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
|
|
||||||
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):
|
|
||||||
self.queue = collections.deque(maxlen=16)
|
|
||||||
|
|
||||||
def add(self, lvm_exec_meta):
|
|
||||||
self.queue.append(lvm_exec_meta)
|
|
||||||
|
|
||||||
def dump(self):
|
|
||||||
with cmd_lock:
|
|
||||||
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()
|
|
||||||
|
|
||||||
|
|
||||||
def _debug_c(cmd, exit_code, out):
|
|
||||||
log_error('CMD= %s' % ' '.join(cmd))
|
|
||||||
log_error(("EC= %d" % exit_code))
|
|
||||||
log_error(("STDOUT=\n %s\n" % out[0]))
|
|
||||||
log_error(("STDERR=\n %s\n" % out[1]))
|
|
||||||
|
|
||||||
|
|
||||||
def call_lvm(command, debug=False):
|
|
||||||
"""
|
|
||||||
Call an executable and return a tuple of exitcode, stdout, stderr
|
|
||||||
:param command: Command to execute
|
|
||||||
:param debug: Dump debug to stdout
|
|
||||||
"""
|
|
||||||
# print 'STACK:'
|
|
||||||
# for line in traceback.format_stack():
|
|
||||||
# print line.strip()
|
|
||||||
|
|
||||||
# Prepend the full lvm executable so that we can run different versions
|
|
||||||
# in different locations on the same box
|
|
||||||
command.insert(0, cfg.LVM_CMD)
|
|
||||||
|
|
||||||
process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True)
|
|
||||||
out = process.communicate()
|
|
||||||
|
|
||||||
stdout_text = bytes(out[0]).decode("utf-8")
|
|
||||||
stderr_text = bytes(out[1]).decode("utf-8")
|
|
||||||
|
|
||||||
if debug or process.returncode != 0:
|
|
||||||
_debug_c(command, process.returncode, (stdout_text, stderr_text))
|
|
||||||
|
|
||||||
if process.returncode == 0:
|
|
||||||
if cfg.DEBUG and out[1] and len(out[1]) and 'help' not in command:
|
|
||||||
log_error('WARNING: lvm is out-putting text to STDERR on success!')
|
|
||||||
_debug_c(command, process.returncode, (stdout_text, stderr_text))
|
|
||||||
|
|
||||||
return process.returncode, stdout_text, stderr_text
|
|
||||||
|
|
||||||
|
|
||||||
def _shell_cfg():
|
|
||||||
global _t_call
|
|
||||||
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:
|
|
||||||
_t_call = None
|
|
||||||
if shell:
|
|
||||||
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):
|
|
||||||
global total_time
|
|
||||||
global total_count
|
|
||||||
|
|
||||||
with cmd_lock:
|
|
||||||
start = time.time()
|
|
||||||
results = _t_call(command, debug)
|
|
||||||
ended = time.time()
|
|
||||||
total_time += (ended - start)
|
|
||||||
total_count += 1
|
|
||||||
cfg.blackbox.add(LvmExecutionMeta(start, ended, command, *results))
|
|
||||||
return results
|
|
||||||
|
|
||||||
|
|
||||||
call = time_wrapper
|
|
||||||
|
|
||||||
|
|
||||||
# Default cmd
|
|
||||||
# Place default arguments for every command here.
|
|
||||||
def _dc(cmd, args):
|
|
||||||
c = [cmd, '--noheading', '--separator', '%s' % SEP, '--nosuffix',
|
|
||||||
'--unbuffered', '--units', 'b']
|
|
||||||
c.extend(args)
|
|
||||||
return c
|
|
||||||
|
|
||||||
|
|
||||||
def parse(out):
|
|
||||||
rc = []
|
|
||||||
|
|
||||||
for line in out.split('\n'):
|
|
||||||
# This line includes separators, so process them
|
|
||||||
if SEP in line:
|
|
||||||
elem = line.split(SEP)
|
|
||||||
cleaned_elem = []
|
|
||||||
for e in elem:
|
|
||||||
e = e.strip()
|
|
||||||
cleaned_elem.append(e)
|
|
||||||
|
|
||||||
if len(cleaned_elem) > 1:
|
|
||||||
rc.append(cleaned_elem)
|
|
||||||
else:
|
|
||||||
t = line.strip()
|
|
||||||
if len(t) > 0:
|
|
||||||
rc.append(t)
|
|
||||||
return rc
|
|
||||||
|
|
||||||
|
|
||||||
def parse_column_names(out, column_names):
|
|
||||||
lines = parse(out)
|
|
||||||
rc = []
|
|
||||||
|
|
||||||
for i in range(0, len(lines)):
|
|
||||||
d = dict(list(zip(column_names, lines[i])))
|
|
||||||
rc.append(d)
|
|
||||||
|
|
||||||
return rc
|
|
||||||
|
|
||||||
|
|
||||||
def options_to_cli_args(options):
|
|
||||||
rc = []
|
|
||||||
for k, v in list(dict(options).items()):
|
|
||||||
if k.startswith("-"):
|
|
||||||
rc.append(k)
|
|
||||||
else:
|
|
||||||
rc.append("--%s" % k)
|
|
||||||
if v != "":
|
|
||||||
rc.append(str(v))
|
|
||||||
return rc
|
|
||||||
|
|
||||||
|
|
||||||
def pv_remove(device, remove_options):
|
|
||||||
cmd = ['pvremove']
|
|
||||||
cmd.extend(options_to_cli_args(remove_options))
|
|
||||||
cmd.append(device)
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def _tag(operation, what, add, rm, tag_options):
|
|
||||||
cmd = [operation]
|
|
||||||
cmd.extend(options_to_cli_args(tag_options))
|
|
||||||
|
|
||||||
if isinstance(what, list):
|
|
||||||
cmd.extend(what)
|
|
||||||
else:
|
|
||||||
cmd.append(what)
|
|
||||||
|
|
||||||
if add:
|
|
||||||
cmd.extend(list(chain.from_iterable(('--addtag', x) for x in add)))
|
|
||||||
if rm:
|
|
||||||
cmd.extend(list(chain.from_iterable(('--deltag', x) for x in rm)))
|
|
||||||
|
|
||||||
return call(cmd, False)
|
|
||||||
|
|
||||||
|
|
||||||
def pv_tag(pv_devices, add, rm, tag_options):
|
|
||||||
return _tag('pvchange', pv_devices, add, rm, tag_options)
|
|
||||||
|
|
||||||
|
|
||||||
def vg_tag(vg_name, add, rm, tag_options):
|
|
||||||
return _tag('vgchange', vg_name, add, rm, tag_options)
|
|
||||||
|
|
||||||
|
|
||||||
def lv_tag(lv_name, add, rm, tag_options):
|
|
||||||
return _tag('lvchange', lv_name, add, rm, tag_options)
|
|
||||||
|
|
||||||
|
|
||||||
def vg_rename(vg, new_name, rename_options):
|
|
||||||
cmd = ['vgrename']
|
|
||||||
cmd.extend(options_to_cli_args(rename_options))
|
|
||||||
cmd.extend([vg, new_name])
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def vg_remove(vg_name, remove_options):
|
|
||||||
cmd = ['vgremove']
|
|
||||||
cmd.extend(options_to_cli_args(remove_options))
|
|
||||||
cmd.extend(['-f', vg_name])
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def vg_lv_create(vg_name, create_options, name, size_bytes, pv_dests):
|
|
||||||
cmd = ['lvcreate']
|
|
||||||
cmd.extend(options_to_cli_args(create_options))
|
|
||||||
cmd.extend(['--size', str(size_bytes) + 'B'])
|
|
||||||
cmd.extend(['--name', name, vg_name])
|
|
||||||
pv_dest_ranges(cmd, pv_dests)
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def vg_lv_snapshot(vg_name, snapshot_options, name, size_bytes):
|
|
||||||
cmd = ['lvcreate']
|
|
||||||
cmd.extend(options_to_cli_args(snapshot_options))
|
|
||||||
cmd.extend(["-s"])
|
|
||||||
|
|
||||||
if size_bytes != 0:
|
|
||||||
cmd.extend(['--size', str(size_bytes) + 'B'])
|
|
||||||
|
|
||||||
cmd.extend(['--name', name, vg_name])
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def vg_lv_create_linear(vg_name, create_options, name, 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(['--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 = ['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:
|
|
||||||
cmd.extend(['--stripesize', str(stripe_size_kb)])
|
|
||||||
|
|
||||||
cmd.extend(['--name', name, vg_name])
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def _vg_lv_create_raid(vg_name, create_options, name, raid_type, size_bytes,
|
|
||||||
num_stripes, stripe_size_kb):
|
|
||||||
cmd = ['lvcreate']
|
|
||||||
|
|
||||||
cmd.extend(options_to_cli_args(create_options))
|
|
||||||
|
|
||||||
cmd.extend(['--type', raid_type])
|
|
||||||
cmd.extend(['--size', str(size_bytes) + 'B'])
|
|
||||||
|
|
||||||
if num_stripes != 0:
|
|
||||||
cmd.extend(['--stripes', str(num_stripes)])
|
|
||||||
|
|
||||||
if stripe_size_kb != 0:
|
|
||||||
cmd.extend(['--stripesize', str(stripe_size_kb)])
|
|
||||||
|
|
||||||
cmd.extend(['--name', name, vg_name])
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def vg_lv_create_raid(vg_name, create_options, name, raid_type, size_bytes,
|
|
||||||
num_stripes, stripe_size_kb):
|
|
||||||
cmd = ['lvcreate']
|
|
||||||
cmd.extend(options_to_cli_args(create_options))
|
|
||||||
|
|
||||||
return _vg_lv_create_raid(vg_name, create_options, name, raid_type,
|
|
||||||
size_bytes, num_stripes, stripe_size_kb)
|
|
||||||
|
|
||||||
|
|
||||||
def vg_lv_create_mirror(vg_name, create_options, name, size_bytes, num_copies):
|
|
||||||
cmd = ['lvcreate']
|
|
||||||
cmd.extend(options_to_cli_args(create_options))
|
|
||||||
|
|
||||||
cmd.extend(['--type', 'mirror'])
|
|
||||||
cmd.extend(['--mirrors', str(num_copies)])
|
|
||||||
cmd.extend(['--size', str(size_bytes) + 'B'])
|
|
||||||
cmd.extend(['--name', name, vg_name])
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def vg_create_cache_pool(md_full_name, data_full_name, create_options):
|
|
||||||
cmd = ['lvconvert']
|
|
||||||
cmd.extend(options_to_cli_args(create_options))
|
|
||||||
cmd.extend(['--type', 'cache-pool', '--force', '-y',
|
|
||||||
'--poolmetadata', md_full_name, data_full_name])
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def vg_create_thin_pool(md_full_name, data_full_name, create_options):
|
|
||||||
cmd = ['lvconvert']
|
|
||||||
cmd.extend(options_to_cli_args(create_options))
|
|
||||||
cmd.extend(['--type', 'thin-pool', '--force', '-y',
|
|
||||||
'--poolmetadata', md_full_name, data_full_name])
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def lv_remove(lv_path, remove_options):
|
|
||||||
cmd = ['lvremove']
|
|
||||||
cmd.extend(options_to_cli_args(remove_options))
|
|
||||||
cmd.extend(['-f', lv_path])
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def lv_rename(lv_path, new_name, rename_options):
|
|
||||||
cmd = ['lvrename']
|
|
||||||
cmd.extend(options_to_cli_args(rename_options))
|
|
||||||
cmd.extend([lv_path, new_name])
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def lv_resize(lv_full_name, size_change, pv_dests,
|
|
||||||
resize_options):
|
|
||||||
cmd = ['lvresize', '--force']
|
|
||||||
|
|
||||||
cmd.extend(options_to_cli_args(resize_options))
|
|
||||||
|
|
||||||
if size_change < 0:
|
|
||||||
cmd.append("-L-%dB" % (-size_change))
|
|
||||||
else:
|
|
||||||
cmd.append("-L+%dB" % (size_change))
|
|
||||||
|
|
||||||
cmd.append(lv_full_name)
|
|
||||||
pv_dest_ranges(cmd, pv_dests)
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def lv_lv_create(lv_full_name, create_options, name, size_bytes):
|
|
||||||
cmd = ['lvcreate']
|
|
||||||
cmd.extend(options_to_cli_args(create_options))
|
|
||||||
cmd.extend(['--virtualsize', str(size_bytes) + 'B', '-T'])
|
|
||||||
cmd.extend(['--name', name, lv_full_name])
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
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(['--type', 'cache', '--cachepool',
|
|
||||||
cache_pool_full_name, lv_full_name])
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def lv_detach_cache(lv_full_name, detach_options, destroy_cache):
|
|
||||||
cmd = ['lvconvert']
|
|
||||||
if destroy_cache:
|
|
||||||
option = '--uncache'
|
|
||||||
else:
|
|
||||||
# Currently fairly dangerous
|
|
||||||
# see: https://bugzilla.redhat.com/show_bug.cgi?id=1248972
|
|
||||||
option = '--splitcache'
|
|
||||||
cmd.extend(options_to_cli_args(detach_options))
|
|
||||||
# needed to prevent interactive questions
|
|
||||||
cmd.extend(["--yes", "--force"])
|
|
||||||
cmd.extend([option, lv_full_name])
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def supports_json():
|
|
||||||
cmd = ['help']
|
|
||||||
rc, out, err = call(cmd)
|
|
||||||
if rc == 0:
|
|
||||||
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_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']
|
|
||||||
|
|
||||||
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:
|
|
||||||
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']
|
|
||||||
|
|
||||||
# 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):
|
|
||||||
cmd = _dc('pvs', ['-o', ','.join(columns)])
|
|
||||||
|
|
||||||
if device:
|
|
||||||
cmd.extend(device)
|
|
||||||
|
|
||||||
rc, out, err = call(cmd)
|
|
||||||
|
|
||||||
if rc == 0:
|
|
||||||
d = parse_column_names(out, columns)
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
def pv_resize(device, size_bytes, create_options):
|
|
||||||
cmd = ['pvresize']
|
|
||||||
|
|
||||||
cmd.extend(options_to_cli_args(create_options))
|
|
||||||
|
|
||||||
if size_bytes != 0:
|
|
||||||
cmd.extend(['--setphysicalvolumesize', str(size_bytes) + 'B'])
|
|
||||||
|
|
||||||
cmd.extend([device])
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def pv_create(create_options, devices):
|
|
||||||
cmd = ['pvcreate', '-ff']
|
|
||||||
cmd.extend(options_to_cli_args(create_options))
|
|
||||||
cmd.extend(devices)
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def pv_allocatable(device, yes, allocation_options):
|
|
||||||
yn = 'n'
|
|
||||||
|
|
||||||
if yes:
|
|
||||||
yn = 'y'
|
|
||||||
|
|
||||||
cmd = ['pvchange']
|
|
||||||
cmd.extend(options_to_cli_args(allocation_options))
|
|
||||||
cmd.extend(['-x', yn, device])
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def pv_scan(activate, cache, device_paths, major_minors, scan_options):
|
|
||||||
cmd = ['pvscan']
|
|
||||||
cmd.extend(options_to_cli_args(scan_options))
|
|
||||||
|
|
||||||
if activate:
|
|
||||||
cmd.extend(['--activate', "ay"])
|
|
||||||
|
|
||||||
if cache:
|
|
||||||
cmd.append('--cache')
|
|
||||||
|
|
||||||
if len(device_paths) > 0:
|
|
||||||
for d in device_paths:
|
|
||||||
cmd.append(d)
|
|
||||||
|
|
||||||
if len(major_minors) > 0:
|
|
||||||
for mm in major_minors:
|
|
||||||
cmd.append("%s:%s" % (mm))
|
|
||||||
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def vg_create(create_options, pv_devices, name):
|
|
||||||
cmd = ['vgcreate']
|
|
||||||
cmd.extend(options_to_cli_args(create_options))
|
|
||||||
cmd.append(name)
|
|
||||||
cmd.extend(pv_devices)
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def vg_change(change_options, name):
|
|
||||||
cmd = ['vgchange']
|
|
||||||
cmd.extend(options_to_cli_args(change_options))
|
|
||||||
cmd.append(name)
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def vg_reduce(vg_name, missing, pv_devices, reduce_options):
|
|
||||||
cmd = ['vgreduce']
|
|
||||||
cmd.extend(options_to_cli_args(reduce_options))
|
|
||||||
|
|
||||||
if len(pv_devices) == 0:
|
|
||||||
cmd.append('--all')
|
|
||||||
if missing:
|
|
||||||
cmd.append('--removemissing')
|
|
||||||
|
|
||||||
cmd.append(vg_name)
|
|
||||||
cmd.extend(pv_devices)
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def vg_extend(vg_name, extend_devices, extend_options):
|
|
||||||
cmd = ['vgextend']
|
|
||||||
cmd.extend(options_to_cli_args(extend_options))
|
|
||||||
cmd.append(vg_name)
|
|
||||||
cmd.extend(extend_devices)
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def _vg_value_set(name, arguments, options):
|
|
||||||
cmd = ['vgchange']
|
|
||||||
cmd.extend(options_to_cli_args(options))
|
|
||||||
cmd.append(name)
|
|
||||||
cmd.extend(arguments)
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def vg_allocation_policy(vg_name, policy, policy_options):
|
|
||||||
return _vg_value_set(vg_name, ['--alloc', policy], policy_options)
|
|
||||||
|
|
||||||
|
|
||||||
def vg_max_pv(vg_name, number, max_options):
|
|
||||||
return _vg_value_set(vg_name, ['--maxphysicalvolumes', str(number)],
|
|
||||||
max_options)
|
|
||||||
|
|
||||||
|
|
||||||
def vg_max_lv(vg_name, number, max_options):
|
|
||||||
return _vg_value_set(vg_name, ['-l', str(number)], max_options)
|
|
||||||
|
|
||||||
|
|
||||||
def vg_uuid_gen(vg_name, ignore, options):
|
|
||||||
assert ignore is None
|
|
||||||
return _vg_value_set(vg_name, ['--uuid'], options)
|
|
||||||
|
|
||||||
|
|
||||||
def activate_deactivate(op, name, activate, control_flags, options):
|
|
||||||
cmd = [op]
|
|
||||||
cmd.extend(options_to_cli_args(options))
|
|
||||||
|
|
||||||
op = '-a'
|
|
||||||
|
|
||||||
if control_flags:
|
|
||||||
# Autoactivation
|
|
||||||
if (1 << 0) & control_flags:
|
|
||||||
op += 'a'
|
|
||||||
# Exclusive locking (Cluster)
|
|
||||||
if (1 << 1) & control_flags:
|
|
||||||
op += 'e'
|
|
||||||
|
|
||||||
# Local node activation
|
|
||||||
if (1 << 2) & control_flags:
|
|
||||||
op += 'l'
|
|
||||||
|
|
||||||
# Activation modes
|
|
||||||
if (1 << 3) & control_flags:
|
|
||||||
cmd.extend(['--activationmode', 'complete'])
|
|
||||||
elif (1 << 4) & control_flags:
|
|
||||||
cmd.extend(['--activationmode', 'partial'])
|
|
||||||
|
|
||||||
# Ignore activation skip
|
|
||||||
if (1 << 5) & control_flags:
|
|
||||||
cmd.append('--ignoreactivationskip')
|
|
||||||
|
|
||||||
if activate:
|
|
||||||
op += 'y'
|
|
||||||
else:
|
|
||||||
op += 'n'
|
|
||||||
|
|
||||||
cmd.append(op)
|
|
||||||
cmd.append(name)
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def vg_retrieve(vg_specific):
|
|
||||||
if vg_specific:
|
|
||||||
assert isinstance(vg_specific, list)
|
|
||||||
|
|
||||||
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']
|
|
||||||
|
|
||||||
cmd = _dc('vgs', ['-o', ','.join(columns)])
|
|
||||||
|
|
||||||
if vg_specific:
|
|
||||||
cmd.extend(vg_specific)
|
|
||||||
|
|
||||||
d = []
|
|
||||||
rc, out, err = call(cmd)
|
|
||||||
if rc == 0:
|
|
||||||
d = parse_column_names(out, columns)
|
|
||||||
|
|
||||||
return d
|
|
||||||
|
|
||||||
|
|
||||||
def lv_retrieve_with_segments():
|
|
||||||
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', 'seg_pe_ranges', 'segtype', 'lv_parent',
|
|
||||||
'lv_role', 'lv_layout']
|
|
||||||
|
|
||||||
cmd = _dc('lvs', ['-a', '-o', ','.join(columns)])
|
|
||||||
rc, out, err = call(cmd)
|
|
||||||
|
|
||||||
d = []
|
|
||||||
|
|
||||||
if rc == 0:
|
|
||||||
d = parse_column_names(out, columns)
|
|
||||||
|
|
||||||
return d
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
pv_data = pv_retrieve_with_segs()
|
|
||||||
|
|
||||||
for p in pv_data:
|
|
||||||
log_debug(str(p))
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
# 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/>.
|
|
||||||
|
|
||||||
from .pv import load_pvs
|
|
||||||
from .vg import load_vgs
|
|
||||||
from .lv import load_lvs
|
|
||||||
from . import cfg
|
|
||||||
|
|
||||||
|
|
||||||
def load(refresh=True, emit_signal=True, cache_refresh=True, log=True):
|
|
||||||
num_total_changes = 0
|
|
||||||
|
|
||||||
# Go through and load all the PVs, VGs and LVs
|
|
||||||
if cache_refresh:
|
|
||||||
cfg.db.refresh(log)
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
# 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/>.
|
|
||||||
|
|
||||||
from .automatedproperties import AutomatedProperties
|
|
||||||
from .utils import job_obj_path_generate
|
|
||||||
from . import cfg
|
|
||||||
from .cfg import JOB_INTERFACE
|
|
||||||
import dbus
|
|
||||||
import threading
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyPep8Naming
|
|
||||||
class JobState(object):
|
|
||||||
def __init__(self, request=None):
|
|
||||||
self.rlock = threading.RLock()
|
|
||||||
|
|
||||||
self._percent = 0
|
|
||||||
self._complete = False
|
|
||||||
self._request = request
|
|
||||||
self._cond = threading.Condition(self.rlock)
|
|
||||||
self._ec = 0
|
|
||||||
self._stderr = ''
|
|
||||||
|
|
||||||
# This is an lvm command that is just taking too long and doesn't
|
|
||||||
# support background operation
|
|
||||||
if self._request:
|
|
||||||
# Faking the percentage when we don't have one
|
|
||||||
self._percent = 1
|
|
||||||
|
|
||||||
@property
|
|
||||||
def Percent(self):
|
|
||||||
with self.rlock:
|
|
||||||
return self._percent
|
|
||||||
|
|
||||||
@Percent.setter
|
|
||||||
def Percent(self, value):
|
|
||||||
with self.rlock:
|
|
||||||
self._percent = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def Complete(self):
|
|
||||||
with self.rlock:
|
|
||||||
if self._request:
|
|
||||||
self._complete = self._request.is_done()
|
|
||||||
if self._complete:
|
|
||||||
self._percent = 100
|
|
||||||
|
|
||||||
return self._complete
|
|
||||||
|
|
||||||
@Complete.setter
|
|
||||||
def Complete(self, value):
|
|
||||||
with self.rlock:
|
|
||||||
self._complete = value
|
|
||||||
self._cond.notify_all()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def GetError(self):
|
|
||||||
with self.rlock:
|
|
||||||
if self.Complete:
|
|
||||||
if self._request:
|
|
||||||
(rc, error) = self._request.get_errors()
|
|
||||||
return (rc, str(error))
|
|
||||||
else:
|
|
||||||
return (self._ec, self._stderr)
|
|
||||||
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:
|
|
||||||
if self._request:
|
|
||||||
return self._request.result()
|
|
||||||
return '/'
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyPep8Naming
|
|
||||||
class Job(AutomatedProperties):
|
|
||||||
_Percent_meta = ('y', JOB_INTERFACE)
|
|
||||||
_Complete_meta = ('b', JOB_INTERFACE)
|
|
||||||
_Result_meta = ('o', JOB_INTERFACE)
|
|
||||||
_GetError_meta = ('(is)', JOB_INTERFACE)
|
|
||||||
|
|
||||||
def __init__(self, request, job_state=None):
|
|
||||||
super(Job, self).__init__(job_obj_path_generate())
|
|
||||||
self.set_interface(JOB_INTERFACE)
|
|
||||||
|
|
||||||
if job_state:
|
|
||||||
self.state = job_state
|
|
||||||
else:
|
|
||||||
self.state = JobState(request)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def Percent(self):
|
|
||||||
return self.state.Percent
|
|
||||||
|
|
||||||
@Percent.setter
|
|
||||||
def Percent(self, value):
|
|
||||||
self.state.Percent = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def Complete(self):
|
|
||||||
return self.state.Complete
|
|
||||||
|
|
||||||
@Complete.setter
|
|
||||||
def Complete(self, value):
|
|
||||||
self.state.Complete = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def GetError(self):
|
|
||||||
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):
|
|
||||||
if self.state.Complete:
|
|
||||||
cfg.om.remove_object(self, True)
|
|
||||||
self.state.dtor()
|
|
||||||
else:
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
JOB_INTERFACE, 'Job is not complete!')
|
|
||||||
|
|
||||||
@dbus.service.method(dbus_interface=JOB_INTERFACE,
|
|
||||||
in_signature='i',
|
|
||||||
out_signature='b')
|
|
||||||
def Wait(self, timeout):
|
|
||||||
return self.state.Wait(timeout)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def Result(self):
|
|
||||||
return self.state.Result
|
|
||||||
|
|
||||||
@property
|
|
||||||
def lvm_id(self):
|
|
||||||
return str(id(self))
|
|
||||||
|
|
||||||
@property
|
|
||||||
def Uuid(self):
|
|
||||||
import uuid
|
|
||||||
return uuid.uuid1()
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
# 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/>.
|
|
||||||
|
|
||||||
from . import cfg
|
|
||||||
|
|
||||||
|
|
||||||
def _compare_construction(o_state, new_state):
|
|
||||||
# We need to check to see if the objects would get constructed
|
|
||||||
# the same
|
|
||||||
existing_ctor, existing_path = o_state.creation_signature()
|
|
||||||
new_ctor, new_path = new_state.creation_signature()
|
|
||||||
|
|
||||||
# print("%s == %s and %s == %s" % (str(existing_ctor), str(new_ctor),
|
|
||||||
# str(existing_path), str(new_path)))
|
|
||||||
|
|
||||||
return ((existing_ctor == new_ctor) and (existing_path == new_path))
|
|
||||||
|
|
||||||
|
|
||||||
def common(retrieve, o_type, search_keys,
|
|
||||||
object_path, refresh, emit_signal, cache_refresh):
|
|
||||||
num_changes = 0
|
|
||||||
existing_paths = []
|
|
||||||
rc = []
|
|
||||||
|
|
||||||
if search_keys:
|
|
||||||
assert isinstance(search_keys, list)
|
|
||||||
|
|
||||||
if cache_refresh:
|
|
||||||
cfg.db.refresh()
|
|
||||||
|
|
||||||
objects = retrieve(search_keys, cache_refresh=False)
|
|
||||||
|
|
||||||
# If we are doing a refresh we need to know what we have in memory, what's
|
|
||||||
# in lvm and add those that are new and remove those that are gone!
|
|
||||||
if refresh:
|
|
||||||
existing_paths = cfg.om.object_paths_by_type(o_type)
|
|
||||||
|
|
||||||
for o in objects:
|
|
||||||
# Assume we need to add this one to dbus, unless we are refreshing
|
|
||||||
# and it's already present
|
|
||||||
return_object = True
|
|
||||||
|
|
||||||
if refresh:
|
|
||||||
# We are refreshing all the PVs from LVM, if this one exists
|
|
||||||
# we need to refresh our state.
|
|
||||||
dbus_object = cfg.om.get_object_by_uuid_lvm_id(*o.identifiers())
|
|
||||||
|
|
||||||
if dbus_object:
|
|
||||||
del existing_paths[dbus_object.dbus_object_path()]
|
|
||||||
|
|
||||||
# If the old object state and new object state wouldn't be
|
|
||||||
# created with the same path and same object constructor we
|
|
||||||
# need to remove the old object and construct the new one
|
|
||||||
# instead!
|
|
||||||
if not _compare_construction(dbus_object.state, o):
|
|
||||||
# Remove existing and construct new one
|
|
||||||
cfg.om.remove_object(dbus_object, emit_signal)
|
|
||||||
dbus_object = o.create_dbus_object(None)
|
|
||||||
cfg.om.register_object(dbus_object, emit_signal)
|
|
||||||
num_changes += 1
|
|
||||||
else:
|
|
||||||
num_changes += dbus_object.refresh(object_state=o)
|
|
||||||
return_object = False
|
|
||||||
|
|
||||||
if return_object:
|
|
||||||
dbus_object = o.create_dbus_object(object_path)
|
|
||||||
cfg.om.register_object(dbus_object, emit_signal)
|
|
||||||
rc.append(dbus_object)
|
|
||||||
|
|
||||||
object_path = None
|
|
||||||
|
|
||||||
if refresh:
|
|
||||||
for k in list(existing_paths.keys()):
|
|
||||||
cfg.om.remove_object(cfg.om.get_object_by_path(k), True)
|
|
||||||
num_changes += 1
|
|
||||||
|
|
||||||
num_changes += len(rc)
|
|
||||||
|
|
||||||
return rc, num_changes
|
|
||||||
@@ -1,893 +0,0 @@
|
|||||||
# 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/>.
|
|
||||||
|
|
||||||
from .automatedproperties import AutomatedProperties
|
|
||||||
|
|
||||||
from . import utils
|
|
||||||
from .utils import vg_obj_path_generate
|
|
||||||
import dbus
|
|
||||||
from . import cmdhandler
|
|
||||||
from . import cfg
|
|
||||||
from .cfg import LV_INTERFACE, THIN_POOL_INTERFACE, SNAPSHOT_INTERFACE, \
|
|
||||||
LV_COMMON_INTERFACE, CACHE_POOL_INTERFACE, LV_CACHED
|
|
||||||
from .request import RequestEntry
|
|
||||||
from .utils import n, n32
|
|
||||||
from .loader import common
|
|
||||||
from .state import State
|
|
||||||
from . import background
|
|
||||||
from .utils import round_size
|
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyUnusedLocal
|
|
||||||
def lvs_state_retrieve(selection, cache_refresh=True):
|
|
||||||
rc = []
|
|
||||||
|
|
||||||
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:
|
|
||||||
rc.append(LvState(
|
|
||||||
l['lv_uuid'], l['lv_name'],
|
|
||||||
l['lv_path'], n(l['lv_size']),
|
|
||||||
l['vg_name'],
|
|
||||||
l['vg_uuid'], l['pool_lv_uuid'],
|
|
||||||
l['pool_lv'], l['origin_uuid'], l['origin'],
|
|
||||||
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']))
|
|
||||||
return rc
|
|
||||||
|
|
||||||
|
|
||||||
def load_lvs(lv_name=None, object_path=None, refresh=False, emit_signal=False,
|
|
||||||
cache_refresh=True):
|
|
||||||
# noinspection PyUnresolvedReferences
|
|
||||||
return common(
|
|
||||||
lvs_state_retrieve,
|
|
||||||
(LvCommon, Lv, LvThinPool, LvSnapShot),
|
|
||||||
lv_name, object_path, refresh, emit_signal, cache_refresh)
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyPep8Naming,PyUnresolvedReferences,PyUnusedLocal
|
|
||||||
class LvState(State):
|
|
||||||
@staticmethod
|
|
||||||
def _pv_devices(uuid):
|
|
||||||
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, gen_new=False)
|
|
||||||
rc.append((pv_obj, pv_segs))
|
|
||||||
|
|
||||||
return dbus.Array(rc, signature="(oa(tts))")
|
|
||||||
|
|
||||||
def vg_name_lookup(self):
|
|
||||||
return cfg.om.get_object_by_path(self.Vg).Name
|
|
||||||
|
|
||||||
@property
|
|
||||||
def lvm_id(self):
|
|
||||||
return "%s/%s" % (self.vg_name_lookup(), self.Name)
|
|
||||||
|
|
||||||
def identifiers(self):
|
|
||||||
return (self.Uuid, self.lvm_id)
|
|
||||||
|
|
||||||
def _get_hidden_lv(self):
|
|
||||||
rc = dbus.Array([], "o")
|
|
||||||
|
|
||||||
vg_name = self.vg_name_lookup()
|
|
||||||
|
|
||||||
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, gen_new=False)
|
|
||||||
assert 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):
|
|
||||||
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(segtypes)
|
|
||||||
else:
|
|
||||||
self._segs.extend(set(segtypes))
|
|
||||||
|
|
||||||
self.Vg = cfg.om.get_object_path_by_uuid_lvm_id(
|
|
||||||
vg_uuid, vg_name, vg_obj_path_generate)
|
|
||||||
|
|
||||||
self.Devices = LvState._pv_devices(self.Uuid)
|
|
||||||
|
|
||||||
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)
|
|
||||||
else:
|
|
||||||
self.PoolLv = '/'
|
|
||||||
|
|
||||||
if OriginLv:
|
|
||||||
self.OriginLv = \
|
|
||||||
cfg.om.get_object_path_by_uuid_lvm_id(
|
|
||||||
origin_uuid, '%s/%s' % (vg_name, OriginLv),
|
|
||||||
vg_obj_path_generate)
|
|
||||||
else:
|
|
||||||
self.OriginLv = '/'
|
|
||||||
|
|
||||||
self.HiddenLvs = self._get_hidden_lv()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def SegType(self):
|
|
||||||
return self._segs
|
|
||||||
|
|
||||||
def _object_path_create(self):
|
|
||||||
return utils.lv_object_path_method(
|
|
||||||
self.Name, (self.Attr, self.layout, self.role))
|
|
||||||
|
|
||||||
def _object_type_create(self):
|
|
||||||
if self.Attr[0] == 't':
|
|
||||||
return LvThinPool
|
|
||||||
elif self.Attr[0] == 'C':
|
|
||||||
if 'pool' in self.layout:
|
|
||||||
return LvCachePool
|
|
||||||
else:
|
|
||||||
return LvCacheLv
|
|
||||||
elif self.Name[0] == '[':
|
|
||||||
return LvCommon
|
|
||||||
elif self.OriginLv != '/':
|
|
||||||
return LvSnapShot
|
|
||||||
else:
|
|
||||||
return Lv
|
|
||||||
|
|
||||||
def create_dbus_object(self, path):
|
|
||||||
if not path:
|
|
||||||
path = cfg.om.get_object_path_by_uuid_lvm_id(
|
|
||||||
self.Uuid, self.lvm_id, self._object_path_create())
|
|
||||||
|
|
||||||
obj_ctor = self._object_type_create()
|
|
||||||
return obj_ctor(path, self)
|
|
||||||
|
|
||||||
def creation_signature(self):
|
|
||||||
klass = self._object_type_create()
|
|
||||||
path_method = self._object_path_create()
|
|
||||||
return (klass, path_method)
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyPep8Naming
|
|
||||||
@utils.dbus_property(LV_COMMON_INTERFACE, 'Uuid', 's')
|
|
||||||
@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")
|
|
||||||
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)
|
|
||||||
_VolumeType_meta = ("(ss)", LV_COMMON_INTERFACE)
|
|
||||||
_Permissions_meta = ("(ss)", LV_COMMON_INTERFACE)
|
|
||||||
_AllocationPolicy_meta = ("(ss)", LV_COMMON_INTERFACE)
|
|
||||||
_State_meta = ("(ss)", LV_COMMON_INTERFACE)
|
|
||||||
_TargetType_meta = ("(ss)", LV_COMMON_INTERFACE)
|
|
||||||
_Health_meta = ("(ss)", LV_COMMON_INTERFACE)
|
|
||||||
_FixedMinor_meta = ('b', LV_COMMON_INTERFACE)
|
|
||||||
_ZeroBlocks_meta = ('b', LV_COMMON_INTERFACE)
|
|
||||||
_SkipActivation_meta = ('b', LV_COMMON_INTERFACE)
|
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
@property
|
|
||||||
def VolumeType(self):
|
|
||||||
type_map = {'C': 'Cache', 'm': 'mirrored',
|
|
||||||
'M': 'Mirrored without initial sync', 'o': 'origin',
|
|
||||||
'O': 'Origin with merging snapshot', 'r': 'raid',
|
|
||||||
'R': 'Raid without initial sync', 's': 'snapshot',
|
|
||||||
'S': 'merging Snapshot', 'p': 'pvmove',
|
|
||||||
'v': 'virtual', 'i': 'mirror or raid image',
|
|
||||||
'I': 'mirror or raid Image out-of-sync',
|
|
||||||
'l': 'mirror log device', 'c': 'under conversion',
|
|
||||||
'V': 'thin Volume', 't': 'thin pool', 'T': 'Thin pool data',
|
|
||||||
'e': 'raid or pool metadata or pool metadata spare',
|
|
||||||
'-': 'Unspecified'}
|
|
||||||
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 (self.state.Attr[1], type_map[self.state.Attr[1]])
|
|
||||||
|
|
||||||
@property
|
|
||||||
def AllocationPolicy(self):
|
|
||||||
type_map = {'a': 'anywhere', 'A': 'anywhere locked',
|
|
||||||
'c': 'contiguous', 'C': 'contiguous locked',
|
|
||||||
'i': 'inherited', 'I': 'inherited locked',
|
|
||||||
'l': 'cling', 'L': 'cling locked',
|
|
||||||
'n': 'normal', 'N': 'normal locked', '-': 'Unspecified'}
|
|
||||||
return (self.state.Attr[2], type_map[self.state.Attr[2]])
|
|
||||||
|
|
||||||
@property
|
|
||||||
def FixedMinor(self):
|
|
||||||
return self.state.Attr[3] == 'm'
|
|
||||||
|
|
||||||
@property
|
|
||||||
def State(self):
|
|
||||||
type_map = {'a': 'active', 's': 'suspended', 'I': 'Invalid snapshot',
|
|
||||||
'S': 'invalid Suspended snapshot',
|
|
||||||
'm': 'snapshot merge failed',
|
|
||||||
'M': 'suspended snapshot (M)erge failed',
|
|
||||||
'd': 'mapped device present without tables',
|
|
||||||
'i': 'mapped device present with inactive table',
|
|
||||||
'X': 'unknown', '-': 'Unspecified'}
|
|
||||||
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 (self.state.Attr[6], type_map[self.state.Attr[6]])
|
|
||||||
|
|
||||||
@property
|
|
||||||
def ZeroBlocks(self):
|
|
||||||
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 (self.state.Attr[8], type_map[self.state.Attr[8]])
|
|
||||||
|
|
||||||
@property
|
|
||||||
def SkipActivation(self):
|
|
||||||
return self.state.Attr[9] == 'k'
|
|
||||||
|
|
||||||
def vg_name_lookup(self):
|
|
||||||
return self.state.vg_name_lookup()
|
|
||||||
|
|
||||||
def lv_full_name(self):
|
|
||||||
return "%s/%s" % (self.state.vg_name_lookup(), self.state.Name)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def identifiers(self):
|
|
||||||
return self.state.identifiers
|
|
||||||
|
|
||||||
@property
|
|
||||||
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 self.state.Attr[0] == 'V'
|
|
||||||
|
|
||||||
@property
|
|
||||||
def IsThinPool(self):
|
|
||||||
return self.state.Attr[0] == 't'
|
|
||||||
|
|
||||||
@property
|
|
||||||
def Active(self):
|
|
||||||
return self.state.active == "active"
|
|
||||||
|
|
||||||
@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)
|
|
||||||
self.set_interface(LV_INTERFACE)
|
|
||||||
self.state = object_state
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _remove(lv_uuid, lv_name, remove_options):
|
|
||||||
# Make sure we have a dbus object representing it
|
|
||||||
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(
|
|
||||||
dbus_interface=LV_INTERFACE,
|
|
||||||
in_signature='ia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def Remove(self, tmo, remove_options, cb, cbe):
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, Lv._remove,
|
|
||||||
(self.Uuid, self.lvm_id, remove_options),
|
|
||||||
cb, cbe, False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _rename(lv_uuid, lv_name, new_name, rename_options):
|
|
||||||
# Make sure we have a dbus object representing it
|
|
||||||
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(
|
|
||||||
dbus_interface=LV_INTERFACE,
|
|
||||||
in_signature='sia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def Rename(self, name, tmo, rename_options, cb, cbe):
|
|
||||||
utils.validate_lv_name(LV_INTERFACE, self.vg_name_lookup(), name)
|
|
||||||
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, Lv._rename,
|
|
||||||
(self.Uuid, self.lvm_id, name, rename_options),
|
|
||||||
cb, cbe, False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=LV_INTERFACE,
|
|
||||||
in_signature='o(tt)a(ott)ia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
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)
|
|
||||||
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _snap_shot(lv_uuid, lv_name, name, optional_size,
|
|
||||||
snapshot_options):
|
|
||||||
# Make sure we have a dbus object representing it
|
|
||||||
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_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:
|
|
||||||
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,
|
|
||||||
in_signature='stia{sv}',
|
|
||||||
out_signature='(oo)',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def Snapshot(self, name, optional_size, tmo,
|
|
||||||
snapshot_options, cb, cbe):
|
|
||||||
|
|
||||||
utils.validate_lv_name(LV_INTERFACE, self.vg_name_lookup(), name)
|
|
||||||
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, Lv._snap_shot,
|
|
||||||
(self.Uuid, self.lvm_id, name,
|
|
||||||
optional_size, snapshot_options), cb, cbe)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _resize(lv_uuid, lv_name, new_size_bytes, pv_dests_and_ranges,
|
|
||||||
resize_options):
|
|
||||||
# Make sure we have a dbus object representing it
|
|
||||||
pv_dests = []
|
|
||||||
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
|
|
||||||
|
|
||||||
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]))
|
|
||||||
|
|
||||||
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,
|
|
||||||
in_signature='ta(ott)ia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def Resize(self, new_size_bytes, pv_dests_and_ranges, tmo,
|
|
||||||
resize_options, cb, cbe):
|
|
||||||
"""
|
|
||||||
Resize a LV
|
|
||||||
:param new_size_bytes: The requested final size in bytes
|
|
||||||
:param pv_dests_and_ranges: An array of pv object paths and src &
|
|
||||||
dst. segment ranges
|
|
||||||
:param tmo: -1 to wait forever, 0 to return job immediately, else
|
|
||||||
number of seconds to wait for operation to complete
|
|
||||||
before getting a job
|
|
||||||
:param resize_options: key/value hash of options
|
|
||||||
:param cb: Used by framework not client facing API
|
|
||||||
:param cbe: Used by framework not client facing API
|
|
||||||
:return: '/' if complete, else job object path
|
|
||||||
"""
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, Lv._resize,
|
|
||||||
(self.Uuid, self.lvm_id, round_size(new_size_bytes),
|
|
||||||
pv_dests_and_ranges,
|
|
||||||
resize_options), cb, cbe, return_tuple=False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _lv_activate_deactivate(uuid, lv_name, activate, control_flags,
|
|
||||||
options):
|
|
||||||
# Make sure we have a dbus object representing it
|
|
||||||
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,
|
|
||||||
in_signature='tia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def Activate(self, control_flags, tmo, activate_options, cb, cbe):
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, Lv._lv_activate_deactivate,
|
|
||||||
(self.state.Uuid, self.state.lvm_id, True,
|
|
||||||
control_flags, activate_options),
|
|
||||||
cb, cbe, return_tuple=False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
# noinspection PyProtectedMember
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=LV_INTERFACE,
|
|
||||||
in_signature='tia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def Deactivate(self, control_flags, tmo, activate_options, cb, cbe):
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, Lv._lv_activate_deactivate,
|
|
||||||
(self.state.Uuid, self.state.lvm_id, False,
|
|
||||||
control_flags, activate_options),
|
|
||||||
cb, cbe, return_tuple=False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _add_rm_tags(uuid, lv_name, tags_add, tags_del, tag_options):
|
|
||||||
# Make sure we have a dbus object representing it
|
|
||||||
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,
|
|
||||||
in_signature='asia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def TagsAdd(self, tags, tmo, tag_options, cb, cbe):
|
|
||||||
|
|
||||||
for t in tags:
|
|
||||||
utils.validate_tag(LV_INTERFACE, t)
|
|
||||||
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, Lv._add_rm_tags,
|
|
||||||
(self.state.Uuid, self.state.lvm_id,
|
|
||||||
tags, None, tag_options),
|
|
||||||
cb, cbe, return_tuple=False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=LV_INTERFACE,
|
|
||||||
in_signature='asia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def TagsDel(self, tags, tmo, tag_options, cb, cbe):
|
|
||||||
|
|
||||||
for t in tags:
|
|
||||||
utils.validate_tag(LV_INTERFACE, t)
|
|
||||||
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, Lv._add_rm_tags,
|
|
||||||
(self.state.Uuid, self.state.lvm_id,
|
|
||||||
None, tags, tag_options),
|
|
||||||
cb, cbe, return_tuple=False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyPep8Naming
|
|
||||||
class LvThinPool(Lv):
|
|
||||||
_DataLv_meta = ("o", THIN_POOL_INTERFACE)
|
|
||||||
_MetaDataLv_meta = ("o", THIN_POOL_INTERFACE)
|
|
||||||
|
|
||||||
def __init__(self, object_path, object_state):
|
|
||||||
super(LvThinPool, self).__init__(object_path, object_state)
|
|
||||||
self.set_interface(THIN_POOL_INTERFACE)
|
|
||||||
self._data_lv, self._metadata_lv = self._get_data_meta()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def DataLv(self):
|
|
||||||
return self._data_lv
|
|
||||||
|
|
||||||
@property
|
|
||||||
def MetaDataLv(self):
|
|
||||||
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 = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_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,
|
|
||||||
in_signature='stia{sv}',
|
|
||||||
out_signature='(oo)',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def LvCreate(self, name, size_bytes, tmo, create_options, cb, cbe):
|
|
||||||
utils.validate_lv_name(THIN_POOL_INTERFACE, self.vg_name_lookup(), name)
|
|
||||||
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, LvThinPool._lv_create,
|
|
||||||
(self.Uuid, self.lvm_id, name,
|
|
||||||
round_size(size_bytes), create_options), cb, cbe)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
|
|
||||||
# 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 self._data_lv
|
|
||||||
|
|
||||||
@property
|
|
||||||
def MetaDataLv(self):
|
|
||||||
return 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 = 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 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)
|
|
||||||
if rc == 0:
|
|
||||||
# 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!
|
|
||||||
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)
|
|
||||||
|
|
||||||
else:
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
LV_INTERFACE,
|
|
||||||
'Exit code %s, stderr = %s' % (str(rc), err))
|
|
||||||
else:
|
|
||||||
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(
|
|
||||||
dbus_interface=CACHE_POOL_INTERFACE,
|
|
||||||
in_signature='oia{sv}',
|
|
||||||
out_signature='(oo)',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def CacheLv(self, lv_object, tmo, cache_options, cb, cbe):
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, LvCachePool._cache_lv,
|
|
||||||
(self.Uuid, self.lvm_id, lv_object,
|
|
||||||
cache_options), cb, cbe)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyPep8Naming
|
|
||||||
class LvCacheLv(Lv):
|
|
||||||
_CachePool_meta = ("o", LV_CACHED)
|
|
||||||
|
|
||||||
def __init__(self, object_path, object_state):
|
|
||||||
super(LvCacheLv, self).__init__(object_path, object_state)
|
|
||||||
self.set_interface(LV_CACHED)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def CachePool(self):
|
|
||||||
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 = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
|
|
||||||
|
|
||||||
if dbo:
|
|
||||||
|
|
||||||
# Get current cache name
|
|
||||||
cache_pool = cfg.om.get_object_by_path(dbo.CachePool)
|
|
||||||
|
|
||||||
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_path_by_lvm_id(lv_name)
|
|
||||||
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 uncached_lv_path
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=LV_CACHED,
|
|
||||||
in_signature='bia{sv}',
|
|
||||||
out_signature='(oo)',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def DetachCachePool(self, destroy_cache, tmo, detach_options, cb, cbe):
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, LvCacheLv._detach_lv,
|
|
||||||
(self.Uuid, self.lvm_id, detach_options,
|
|
||||||
destroy_cache), cb, cbe)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyPep8Naming
|
|
||||||
class LvSnapShot(Lv):
|
|
||||||
def __init__(self, object_path, object_state):
|
|
||||||
super(LvSnapShot, self).__init__(object_path, object_state)
|
|
||||||
self.set_interface(SNAPSHOT_INTERFACE)
|
|
||||||
|
|
||||||
@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)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
@@ -1,184 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
# 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/>.
|
|
||||||
#
|
|
||||||
# Copyright 2015-2016, Vratislav Podzimek <vpodzime@redhat.com>
|
|
||||||
|
|
||||||
import subprocess
|
|
||||||
import shlex
|
|
||||||
from fcntl import fcntl, F_GETFL, F_SETFL
|
|
||||||
from os import O_NONBLOCK
|
|
||||||
import traceback
|
|
||||||
import sys
|
|
||||||
import re
|
|
||||||
|
|
||||||
try:
|
|
||||||
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> "
|
|
||||||
|
|
||||||
|
|
||||||
def _quote_arg(arg):
|
|
||||||
if len(shlex.split(arg)) > 1:
|
|
||||||
return '"%s"' % arg
|
|
||||||
else:
|
|
||||||
return arg
|
|
||||||
|
|
||||||
|
|
||||||
class LVMShellProxy(object):
|
|
||||||
def _read_until_prompt(self):
|
|
||||||
prev_ec = None
|
|
||||||
stdout = ""
|
|
||||||
while not stdout.endswith(SHELL_PROMPT):
|
|
||||||
try:
|
|
||||||
tmp = self.lvm_shell.stdout.read()
|
|
||||||
if tmp:
|
|
||||||
stdout += tmp.decode("utf-8")
|
|
||||||
except IOError:
|
|
||||||
# nothing written yet
|
|
||||||
pass
|
|
||||||
|
|
||||||
# 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")
|
|
||||||
num_written = self.lvm_shell.stdin.write(cmd_bytes)
|
|
||||||
assert (num_written == len(cmd_bytes))
|
|
||||||
self.lvm_shell.stdin.flush()
|
|
||||||
|
|
||||||
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):
|
|
||||||
self.re = re.compile(".*(\[(-?[0-9]+)\] lvm> $)", re.DOTALL)
|
|
||||||
|
|
||||||
# run the lvm shell
|
|
||||||
self.lvm_shell = subprocess.Popen(
|
|
||||||
[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)
|
|
||||||
|
|
||||||
# wait for the first prompt
|
|
||||||
self._read_until_prompt()
|
|
||||||
|
|
||||||
# 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):
|
|
||||||
# create the command string
|
|
||||||
cmd = " ".join(_quote_arg(arg) for arg in argv)
|
|
||||||
cmd += "\n"
|
|
||||||
|
|
||||||
# run the command by writing it to the shell's STDIN
|
|
||||||
self._write_cmd(cmd)
|
|
||||||
|
|
||||||
# If lvm is utilizing gnu readline, it echos stdin to stdout
|
|
||||||
if self.echo:
|
|
||||||
self._discard_echo(cmd)
|
|
||||||
|
|
||||||
# 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:
|
|
||||||
rc = 0
|
|
||||||
|
|
||||||
if debug or rc != 0:
|
|
||||||
log_error(('CMD: %s' % cmd))
|
|
||||||
log_error(("EC = %d" % rc))
|
|
||||||
log_error(("STDOUT=\n %s\n" % stdout))
|
|
||||||
log_error(("STDERR=\n %s\n" % stderr))
|
|
||||||
|
|
||||||
return (rc, stdout, stderr)
|
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
self.lvm_shell.terminate()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
shell = LVMShellProxy()
|
|
||||||
in_line = "start"
|
|
||||||
try:
|
|
||||||
while in_line:
|
|
||||||
in_line = input("lvm> ")
|
|
||||||
if in_line:
|
|
||||||
ret, out, err, = shell.call_lvm(in_line.split())
|
|
||||||
print(("RET: %d" % ret))
|
|
||||||
print(("OUT:\n%s" % out))
|
|
||||||
print(("ERR:\n%s" % err))
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
pass
|
|
||||||
except EOFError:
|
|
||||||
pass
|
|
||||||
except Exception:
|
|
||||||
traceback.print_exc(file=sys.stdout)
|
|
||||||
finally:
|
|
||||||
print()
|
|
||||||
@@ -1,544 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
# 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/>.
|
|
||||||
|
|
||||||
from collections import OrderedDict
|
|
||||||
|
|
||||||
import pprint as prettyprint
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
try:
|
|
||||||
from . import cmdhandler
|
|
||||||
from .utils import log_debug, log_error
|
|
||||||
except SystemError:
|
|
||||||
import cmdhandler
|
|
||||||
from utils import log_debug
|
|
||||||
|
|
||||||
|
|
||||||
class DataStore(object):
|
|
||||||
def __init__(self, usejson=None):
|
|
||||||
self.pvs = {}
|
|
||||||
self.vgs = {}
|
|
||||||
self.lvs = {}
|
|
||||||
self.pv_lvs = {}
|
|
||||||
self.lv_pvs = {}
|
|
||||||
self.lvs_hidden = {}
|
|
||||||
|
|
||||||
self.pv_path_to_uuid = {}
|
|
||||||
self.vg_name_to_uuid = {}
|
|
||||||
self.lv_full_name_to_uuid = {}
|
|
||||||
|
|
||||||
self.lvs_in_vgs = {}
|
|
||||||
self.pvs_in_vgs = {}
|
|
||||||
|
|
||||||
# self.refresh()
|
|
||||||
self.num_refreshes = 0
|
|
||||||
|
|
||||||
if usejson is None:
|
|
||||||
self.json = cmdhandler.supports_json()
|
|
||||||
else:
|
|
||||||
self.json = usejson
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _insert_record(table, key, record, allowed_multiple):
|
|
||||||
if key in table:
|
|
||||||
existing = table[key]
|
|
||||||
|
|
||||||
for rec_k, rec_v in record.items():
|
|
||||||
if rec_k in allowed_multiple:
|
|
||||||
# This column name allows us to store multiple value for
|
|
||||||
# each type
|
|
||||||
if not isinstance(existing[rec_k], list):
|
|
||||||
existing_value = existing[rec_k]
|
|
||||||
existing[rec_k] = [existing_value, rec_v]
|
|
||||||
else:
|
|
||||||
existing[rec_k].append(rec_v)
|
|
||||||
else:
|
|
||||||
# If something is not expected to have changing values
|
|
||||||
# lets ensure that
|
|
||||||
if existing[rec_k] != rec_v:
|
|
||||||
raise RuntimeError(
|
|
||||||
"existing[%s]=%s != %s" %
|
|
||||||
(rec_k, str(existing[rec_k]),
|
|
||||||
str(rec_v)))
|
|
||||||
else:
|
|
||||||
table[key] = record
|
|
||||||
|
|
||||||
@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'])
|
|
||||||
|
|
||||||
for p in c_pvs.values():
|
|
||||||
# Capture which PVs are associated with which VG
|
|
||||||
if p['vg_uuid'] not in c_pvs_in_vgs:
|
|
||||||
c_pvs_in_vgs[p['vg_uuid']] = []
|
|
||||||
|
|
||||||
if p['vg_name']:
|
|
||||||
c_pvs_in_vgs[p['vg_uuid']].append(
|
|
||||||
(p['pv_name'], p['pv_uuid']))
|
|
||||||
|
|
||||||
# Lookup for translating between /dev/<name> and pv uuid
|
|
||||||
c_lookup[p['pv_name']] = p['pv_uuid']
|
|
||||||
|
|
||||||
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'
|
|
||||||
|
|
||||||
for p in c_pvs.values():
|
|
||||||
# Capture which PVs are associated with which VG
|
|
||||||
if p['vg_uuid'] not in c_pvs_in_vgs:
|
|
||||||
c_pvs_in_vgs[p['vg_uuid']] = []
|
|
||||||
|
|
||||||
if p['vg_name']:
|
|
||||||
c_pvs_in_vgs[p['vg_uuid']].append(
|
|
||||||
(p['pv_name'], p['pv_uuid']))
|
|
||||||
|
|
||||||
# Lookup for translating between /dev/<name> and pv uuid
|
|
||||||
c_lookup[p['pv_name']] = p['pv_uuid']
|
|
||||||
|
|
||||||
return c_pvs, c_lookup, c_pvs_in_vgs
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _parse_vgs(_vgs):
|
|
||||||
vgs = sorted(_vgs, key=lambda vk: vk['vg_name'])
|
|
||||||
|
|
||||||
c_vgs = OrderedDict()
|
|
||||||
c_lookup = {}
|
|
||||||
|
|
||||||
for i in vgs:
|
|
||||||
c_lookup[i['vg_name']] = i['vg_uuid']
|
|
||||||
DataStore._insert_record(c_vgs, i['vg_uuid'], i, [])
|
|
||||||
|
|
||||||
return c_vgs, c_lookup
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _parse_vgs_json(_all):
|
|
||||||
|
|
||||||
tmp_vg = []
|
|
||||||
for r in _all['report']:
|
|
||||||
# Get the pv data for this VG.
|
|
||||||
if 'vg' in r:
|
|
||||||
tmp_vg.extend(r['vg'])
|
|
||||||
|
|
||||||
# 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 c_lvs.values():
|
|
||||||
if i['vg_uuid'] not in c_lvs_in_vgs:
|
|
||||||
c_lvs_in_vgs[i['vg_uuid']] = []
|
|
||||||
|
|
||||||
c_lvs_in_vgs[
|
|
||||||
i['vg_uuid']].append(
|
|
||||||
(i['lv_name'],
|
|
||||||
(i['lv_attr'], i['lv_layout'], i['lv_role']),
|
|
||||||
i['lv_uuid']))
|
|
||||||
|
|
||||||
if i['lv_parent']:
|
|
||||||
# Lookup what the parent refers too
|
|
||||||
parent_name = i['lv_parent']
|
|
||||||
full_parent_name = "%s/%s" % (i['vg_name'], parent_name)
|
|
||||||
if full_parent_name not in c_lv_full_lookup:
|
|
||||||
parent_name = '[%s]' % (parent_name)
|
|
||||||
full_parent_name = "%s/%s" % (i['vg_name'], parent_name)
|
|
||||||
|
|
||||||
parent_uuid = c_lv_full_lookup[full_parent_name]
|
|
||||||
|
|
||||||
if parent_uuid not in c_lvs_hidden:
|
|
||||||
c_lvs_hidden[parent_uuid] = []
|
|
||||||
|
|
||||||
c_lvs_hidden[parent_uuid].append(
|
|
||||||
(i['lv_uuid'], i['lv_name']))
|
|
||||||
|
|
||||||
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):
|
|
||||||
l = [l]
|
|
||||||
return l
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _parse_seg_entry(se, segtype):
|
|
||||||
if se:
|
|
||||||
# print("_parse_seg_entry %s %s" % (str(se), str(segtype)))
|
|
||||||
device, segs = se.split(":")
|
|
||||||
start, end = segs.split('-')
|
|
||||||
return (device, (start, end), segtype)
|
|
||||||
else:
|
|
||||||
return ("", (), segtype)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _build_segments(l, seg_types):
|
|
||||||
rc = []
|
|
||||||
l = DataStore._make_list(l)
|
|
||||||
s = DataStore._make_list(seg_types)
|
|
||||||
|
|
||||||
assert len(l) == len(s)
|
|
||||||
ls = list(zip(l, s))
|
|
||||||
|
|
||||||
for i in ls:
|
|
||||||
if ' ' in i[0]:
|
|
||||||
tmp = i[0].split(' ')
|
|
||||||
for t in tmp:
|
|
||||||
rc.append(DataStore._parse_seg_entry(t, i[1]))
|
|
||||||
else:
|
|
||||||
rc.append(DataStore._parse_seg_entry(*i))
|
|
||||||
return rc
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _pv_device_lv_entry(table, pv_device, lv_uuid, meta, lv_attr,
|
|
||||||
segment_info):
|
|
||||||
|
|
||||||
if pv_device not in table:
|
|
||||||
table[pv_device] = {}
|
|
||||||
|
|
||||||
if lv_uuid not in table[pv_device]:
|
|
||||||
table[pv_device][lv_uuid] = {}
|
|
||||||
table[pv_device][lv_uuid]['segs'] = [segment_info]
|
|
||||||
table[pv_device][lv_uuid]['name'] = meta
|
|
||||||
table[pv_device][lv_uuid]['meta'] = lv_attr
|
|
||||||
else:
|
|
||||||
table[pv_device][lv_uuid]['segs'].append(segment_info)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _pv_device_lv_format(pv_device_lvs):
|
|
||||||
rc = {}
|
|
||||||
|
|
||||||
for pv_device, pd in pv_device_lvs.items():
|
|
||||||
lvs = []
|
|
||||||
for lv_uuid, ld in sorted(pd.items()):
|
|
||||||
lvs.append((lv_uuid, ld['name'], ld['meta'], ld['segs']))
|
|
||||||
|
|
||||||
rc[pv_device] = lvs
|
|
||||||
return rc
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _lvs_device_pv_entry(table, lv_uuid, pv_device, pv_uuid, segment_info):
|
|
||||||
if lv_uuid not in table:
|
|
||||||
table[lv_uuid] = {}
|
|
||||||
|
|
||||||
if pv_device not in table[lv_uuid]:
|
|
||||||
table[lv_uuid][pv_device] = {}
|
|
||||||
table[lv_uuid][pv_device]['segs'] = [segment_info]
|
|
||||||
table[lv_uuid][pv_device]['pv_uuid'] = pv_uuid
|
|
||||||
else:
|
|
||||||
table[lv_uuid][pv_device]['segs'].append(segment_info)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _lvs_device_pv_format(lvs_device_pvs):
|
|
||||||
rc = {}
|
|
||||||
|
|
||||||
for lv_uuid, ld in lvs_device_pvs.items():
|
|
||||||
pvs = []
|
|
||||||
for pv_device, pd in sorted(ld.items()):
|
|
||||||
pvs.append((pd['pv_uuid'], pv_device, pd['segs']))
|
|
||||||
|
|
||||||
rc[lv_uuid] = pvs
|
|
||||||
return rc
|
|
||||||
|
|
||||||
def _parse_pv_in_lvs(self):
|
|
||||||
pv_device_lvs = {} # What LVs are stored on a PV
|
|
||||||
lvs_device_pv = {} # Where LV data is stored
|
|
||||||
|
|
||||||
for i in self.lvs.values():
|
|
||||||
segs = self._build_segments(i['seg_pe_ranges'], i['segtype'])
|
|
||||||
for s in segs:
|
|
||||||
# We are referring to physical device
|
|
||||||
if '/dev/' in s[0]:
|
|
||||||
device, r, seg_type = s
|
|
||||||
|
|
||||||
DataStore._pv_device_lv_entry(
|
|
||||||
pv_device_lvs, device, i['lv_uuid'], i['lv_name'],
|
|
||||||
(i['lv_attr'], i['lv_layout'], i['lv_role']),
|
|
||||||
(r[0], r[1], seg_type))
|
|
||||||
|
|
||||||
# (pv_name, pv_segs, pv_uuid)
|
|
||||||
DataStore._lvs_device_pv_entry(
|
|
||||||
lvs_device_pv, i['lv_uuid'], device,
|
|
||||||
self.pv_path_to_uuid[device], (r[0], r[1], seg_type))
|
|
||||||
else:
|
|
||||||
# TODO Handle the case where the segments refer to a LV
|
|
||||||
# and not a PV
|
|
||||||
pass
|
|
||||||
# print("Handle this %s %s %s" % (s[0], s[1], s[2]))
|
|
||||||
|
|
||||||
# Convert form to needed result for consumption
|
|
||||||
pv_device_lvs_result = DataStore._pv_device_lv_format(pv_device_lvs)
|
|
||||||
lvs_device_pv_result = DataStore._lvs_device_pv_format(lvs_device_pv)
|
|
||||||
|
|
||||||
return pv_device_lvs_result, lvs_device_pv_result
|
|
||||||
|
|
||||||
def refresh(self, log=True):
|
|
||||||
"""
|
|
||||||
Go out and query lvm for the latest data in as few trips as possible
|
|
||||||
:param log Add debug log entry/exit messages
|
|
||||||
:return: None
|
|
||||||
"""
|
|
||||||
self.num_refreshes += 1
|
|
||||||
if log:
|
|
||||||
log_debug("lvmdb - refresh entry")
|
|
||||||
|
|
||||||
# Grab everything first then parse it
|
|
||||||
if self.json:
|
|
||||||
# Do a single lvm retrieve for everything in json
|
|
||||||
a = cmdhandler.lvm_full_report_json()
|
|
||||||
|
|
||||||
_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)
|
|
||||||
|
|
||||||
# Set all
|
|
||||||
self.pvs = _pvs
|
|
||||||
self.pv_path_to_uuid = _pvs_lookup
|
|
||||||
self.vg_name_to_uuid = _vgs_lookup
|
|
||||||
self.lv_full_name_to_uuid = _lvs_lookup
|
|
||||||
|
|
||||||
self.vgs = _vgs
|
|
||||||
self.lvs = _lvs
|
|
||||||
self.lvs_in_vgs = _lvs_in_vgs
|
|
||||||
self.pvs_in_vgs = _pvs_in_vgs
|
|
||||||
self.lvs_hidden = _lvs_hidden
|
|
||||||
|
|
||||||
# Create lookup table for which LV and segments are on each PV
|
|
||||||
self.pv_lvs, self.lv_pvs = self._parse_pv_in_lvs()
|
|
||||||
|
|
||||||
if log:
|
|
||||||
log_debug("lvmdb - refresh exit")
|
|
||||||
|
|
||||||
def fetch_pvs(self, pv_name):
|
|
||||||
if not pv_name:
|
|
||||||
return self.pvs.values()
|
|
||||||
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 fetch_vgs(self, vg_name):
|
|
||||||
if not vg_name:
|
|
||||||
return self.vgs.values()
|
|
||||||
else:
|
|
||||||
rc = []
|
|
||||||
for s in vg_name:
|
|
||||||
rc.append(self.vgs[self.vg_name_to_uuid[s]])
|
|
||||||
return rc
|
|
||||||
|
|
||||||
def fetch_lvs(self, lv_names):
|
|
||||||
try:
|
|
||||||
if not lv_names:
|
|
||||||
return self.lvs.values()
|
|
||||||
else:
|
|
||||||
rc = []
|
|
||||||
for s in lv_names:
|
|
||||||
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")
|
|
||||||
for keys in sorted(self.lv_full_name_to_uuid.keys()):
|
|
||||||
log_error("%s" % (keys))
|
|
||||||
log_error("lvs entries by uuid")
|
|
||||||
for keys in sorted(self.lvs.keys()):
|
|
||||||
log_error("%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']))
|
|
||||||
|
|
||||||
def pv_contained_lv(self, pv_device):
|
|
||||||
rc = []
|
|
||||||
if pv_device in self.pv_lvs:
|
|
||||||
rc = self.pv_lvs[pv_device]
|
|
||||||
return rc
|
|
||||||
|
|
||||||
def lv_contained_pv(self, lv_uuid):
|
|
||||||
rc = []
|
|
||||||
if lv_uuid in self.lv_pvs:
|
|
||||||
rc = self.lv_pvs[lv_uuid]
|
|
||||||
return rc
|
|
||||||
|
|
||||||
def lvs_in_vg(self, vg_uuid):
|
|
||||||
# Return an array of
|
|
||||||
# (lv_name, (lv_attr, lv_layout, lv_role), lv_uuid)
|
|
||||||
rc = []
|
|
||||||
if vg_uuid in self.lvs_in_vgs:
|
|
||||||
rc = self.lvs_in_vgs[vg_uuid]
|
|
||||||
return rc
|
|
||||||
|
|
||||||
def pvs_in_vg(self, vg_uuid):
|
|
||||||
# Returns an array of (pv_name, pv_uuid)
|
|
||||||
rc = []
|
|
||||||
if vg_uuid in self.pvs_in_vgs:
|
|
||||||
rc = self.pvs_in_vgs[vg_uuid]
|
|
||||||
return rc
|
|
||||||
|
|
||||||
def hidden_lvs(self, lv_uuid):
|
|
||||||
# For a specified LV, return a list of hidden lv_uuid, lv_name
|
|
||||||
# for it
|
|
||||||
rc = []
|
|
||||||
if lv_uuid in self.lvs_hidden:
|
|
||||||
rc = self.lvs_hidden[lv_uuid]
|
|
||||||
return rc
|
|
||||||
|
|
||||||
|
|
||||||
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.refresh()
|
|
||||||
|
|
||||||
print("PVS")
|
|
||||||
for v in ds.pvs.values():
|
|
||||||
pp.pprint(v)
|
|
||||||
|
|
||||||
print("VGS")
|
|
||||||
for v in ds.vgs.values():
|
|
||||||
pp.pprint(v)
|
|
||||||
|
|
||||||
print("LVS")
|
|
||||||
for v in ds.lvs.values():
|
|
||||||
pp.pprint(v)
|
|
||||||
|
|
||||||
print("LVS in VG")
|
|
||||||
for k, v in ds.lvs_in_vgs.items():
|
|
||||||
print("VG uuid = %s" % (k))
|
|
||||||
pp.pprint(v)
|
|
||||||
|
|
||||||
print("pv_in_lvs")
|
|
||||||
for k, v in ds.pv_lvs.items():
|
|
||||||
print("PV %s contains LVS:" % (k))
|
|
||||||
pp.pprint(v)
|
|
||||||
|
|
||||||
for k, v in ds.lv_pvs.items():
|
|
||||||
print("LV device = %s" % (k))
|
|
||||||
pp.pprint(v)
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
# 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/>.
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import lvmdbusd
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.exit(lvmdbusd.main())
|
|
||||||
@@ -1,182 +0,0 @@
|
|||||||
# 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/>.
|
|
||||||
|
|
||||||
from . import cfg
|
|
||||||
from . import objectmanager
|
|
||||||
from . import utils
|
|
||||||
from .cfg import BASE_INTERFACE, BASE_OBJ_PATH, MANAGER_OBJ_PATH
|
|
||||||
import threading
|
|
||||||
from . import cmdhandler
|
|
||||||
import time
|
|
||||||
import signal
|
|
||||||
import dbus
|
|
||||||
from . import lvmdb
|
|
||||||
# noinspection PyUnresolvedReferences
|
|
||||||
from gi.repository import GLib
|
|
||||||
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
|
|
||||||
import argparse
|
|
||||||
import os
|
|
||||||
from .refresh import handle_external_event, event_complete
|
|
||||||
|
|
||||||
|
|
||||||
class Lvm(objectmanager.ObjectManager):
|
|
||||||
def __init__(self, object_path):
|
|
||||||
super(Lvm, self).__init__(object_path, BASE_INTERFACE)
|
|
||||||
|
|
||||||
|
|
||||||
def _discard_pending_refreshes():
|
|
||||||
# We just handled a refresh, if we have any in the queue they can be
|
|
||||||
# removed because by definition they are older than the refresh we just did.
|
|
||||||
# As we limit the number of refreshes getting into the queue
|
|
||||||
# we should only ever have one to remove.
|
|
||||||
requests = []
|
|
||||||
while not cfg.worker_q.empty():
|
|
||||||
try:
|
|
||||||
r = cfg.worker_q.get(block=False)
|
|
||||||
if r.method != handle_external_event:
|
|
||||||
requests.append(r)
|
|
||||||
else:
|
|
||||||
# Make sure we make this event complete even though it didn't
|
|
||||||
# run, otherwise no other events will get processed
|
|
||||||
event_complete()
|
|
||||||
break
|
|
||||||
except queue.Empty:
|
|
||||||
break
|
|
||||||
|
|
||||||
# Any requests we removed, but did not discard need to be re-queued
|
|
||||||
for r in requests:
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
|
|
||||||
def process_request():
|
|
||||||
while cfg.run.value != 0:
|
|
||||||
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()
|
|
||||||
|
|
||||||
end = cfg.db.num_refreshes
|
|
||||||
|
|
||||||
num_refreshes = end - start
|
|
||||||
|
|
||||||
if num_refreshes > 0:
|
|
||||||
_discard_pending_refreshes()
|
|
||||||
|
|
||||||
if num_refreshes > 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 main():
|
|
||||||
# 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", default=None,
|
|
||||||
dest='use_json')
|
|
||||||
|
|
||||||
use_session = os.getenv('LVMDBUSD_USE_SESSION', False)
|
|
||||||
|
|
||||||
# Ensure that we get consistent output for parsing stdout/stderr
|
|
||||||
os.environ["LC_ALL"] = "C"
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
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:
|
|
||||||
signal.signal(s, utils.handler)
|
|
||||||
except RuntimeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
|
|
||||||
dbus.mainloop.glib.threads_init()
|
|
||||||
|
|
||||||
if use_session:
|
|
||||||
cfg.bus = dbus.SessionBus()
|
|
||||||
else:
|
|
||||||
cfg.bus = dbus.SystemBus()
|
|
||||||
# The base name variable needs to exist for things to work.
|
|
||||||
# noinspection PyUnusedLocal
|
|
||||||
base_name = dbus.service.BusName(BASE_INTERFACE, cfg.bus)
|
|
||||||
cfg.om = Lvm(BASE_OBJ_PATH)
|
|
||||||
cfg.om.register_object(Manager(MANAGER_OBJ_PATH))
|
|
||||||
|
|
||||||
cfg.load = load
|
|
||||||
|
|
||||||
cfg.db = lvmdb.DataStore(args.use_json)
|
|
||||||
|
|
||||||
# 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))
|
|
||||||
|
|
||||||
cfg.load(refresh=False, emit_signal=False)
|
|
||||||
cfg.loop = GLib.MainLoop()
|
|
||||||
|
|
||||||
for process in thread_list:
|
|
||||||
process.damon = True
|
|
||||||
process.start()
|
|
||||||
|
|
||||||
end = time.time()
|
|
||||||
log_debug(
|
|
||||||
'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()
|
|
||||||
|
|
||||||
if args.use_udev:
|
|
||||||
udevwatch.remove()
|
|
||||||
|
|
||||||
for process in thread_list:
|
|
||||||
process.join()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
utils.handler(signal.SIGINT, None)
|
|
||||||
return 0
|
|
||||||
@@ -1,246 +0,0 @@
|
|||||||
# 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/>.
|
|
||||||
|
|
||||||
from .automatedproperties import AutomatedProperties
|
|
||||||
|
|
||||||
from . import utils
|
|
||||||
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 .refresh import event_add
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyPep8Naming
|
|
||||||
class Manager(AutomatedProperties):
|
|
||||||
_Version_meta = ("t", MANAGER_INTERFACE)
|
|
||||||
|
|
||||||
def __init__(self, object_path):
|
|
||||||
super(Manager, self).__init__(object_path)
|
|
||||||
self.set_interface(MANAGER_INTERFACE)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def Version(self):
|
|
||||||
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, None, False)
|
|
||||||
if pv:
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
MANAGER_INTERFACE, "PV Already exists!")
|
|
||||||
|
|
||||||
created_pv = []
|
|
||||||
rc, out, err = cmdhandler.pv_create(create_options, [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,
|
|
||||||
in_signature='sia{sv}',
|
|
||||||
out_signature='(oo)',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def PvCreate(self, device, tmo, create_options, cb, cbe):
|
|
||||||
utils.validate_device_path(MANAGER_INTERFACE, device)
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, Manager._pv_create,
|
|
||||||
(device, create_options), cb, cbe)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _create_vg(name, pv_object_paths, create_options):
|
|
||||||
pv_devices = []
|
|
||||||
|
|
||||||
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(
|
|
||||||
MANAGER_INTERFACE, 'object path = %s not found' % p)
|
|
||||||
|
|
||||||
rc, out, err = cmdhandler.vg_create(create_options, pv_devices, 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,
|
|
||||||
in_signature='saoia{sv}',
|
|
||||||
out_signature='(oo)',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def VgCreate(self, name, pv_object_paths, tmo, create_options, cb, cbe):
|
|
||||||
utils.validate_vg_name(MANAGER_INTERFACE, name)
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, Manager._create_vg,
|
|
||||||
(name, pv_object_paths, create_options,),
|
|
||||||
cb, cbe)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _refresh():
|
|
||||||
utils.log_debug('Manager.Refresh - entry')
|
|
||||||
|
|
||||||
# This is a diagnostic and should not be run in normal operation, so
|
|
||||||
# lets remove the log entries for refresh as it's implied.
|
|
||||||
rc = cfg.load(log=False)
|
|
||||||
|
|
||||||
if rc != 0:
|
|
||||||
utils.log_debug('Manager.Refresh - exit %d' % (rc),
|
|
||||||
'bg_black', 'fg_light_red')
|
|
||||||
else:
|
|
||||||
utils.log_debug('Manager.Refresh - exit %d' % (rc))
|
|
||||||
return rc
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=MANAGER_INTERFACE,
|
|
||||||
out_signature='t',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def Refresh(self, cb, cbe):
|
|
||||||
"""
|
|
||||||
Take all the objects we know about and go out and grab the latest
|
|
||||||
more of a test method at the moment to make sure we are handling object
|
|
||||||
paths correctly.
|
|
||||||
|
|
||||||
:param cb Callback for result
|
|
||||||
:param cbe Callback for errors
|
|
||||||
|
|
||||||
Returns the number of changes, object add/remove/properties changed
|
|
||||||
"""
|
|
||||||
r = RequestEntry(-1, Manager._refresh, (), cb, cbe, False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=MANAGER_INTERFACE,
|
|
||||||
in_signature='s',
|
|
||||||
out_signature='o')
|
|
||||||
def LookUpByLvmId(self, key):
|
|
||||||
"""
|
|
||||||
Given a lvm id in one of the forms:
|
|
||||||
|
|
||||||
/dev/sda
|
|
||||||
some_vg
|
|
||||||
some_vg/some_lv
|
|
||||||
Oe1rPX-Pf0W-15E5-n41N-ZmtF-jXS0-Osg8fn
|
|
||||||
|
|
||||||
return the object path in O(1) time.
|
|
||||||
|
|
||||||
: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, gen_new=False)
|
|
||||||
if p:
|
|
||||||
return p
|
|
||||||
return '/'
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=MANAGER_INTERFACE,
|
|
||||||
in_signature='b')
|
|
||||||
def UseLvmShell(self, yes_no):
|
|
||||||
"""
|
|
||||||
Allow the client to enable/disable lvm shell, used for testing
|
|
||||||
:param yes_no:
|
|
||||||
:return: Nothing
|
|
||||||
"""
|
|
||||||
cmdhandler.set_execution(yes_no)
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=MANAGER_INTERFACE,
|
|
||||||
in_signature='s', out_signature='i')
|
|
||||||
def ExternalEvent(self, command):
|
|
||||||
|
|
||||||
event_add((command,))
|
|
||||||
return dbus.Int32(0)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _pv_scan(activate, cache, device_path, major_minor, scan_options):
|
|
||||||
|
|
||||||
rc, out, err = cmdhandler.pv_scan(
|
|
||||||
activate, cache, device_path,
|
|
||||||
major_minor, scan_options)
|
|
||||||
|
|
||||||
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,
|
|
||||||
in_signature='bbasa(ii)ia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def PvScan(self, activate, cache, device_paths, major_minors,
|
|
||||||
tmo, scan_options, cb, cbe):
|
|
||||||
"""
|
|
||||||
Scan all supported LVM block devices in the system for physical volumes
|
|
||||||
NOTE: major_minors & device_paths only usable when cache == True
|
|
||||||
:param activate: If True, activate any newly found LVs
|
|
||||||
:param cache: If True, update lvmetad
|
|
||||||
:param device_paths: Array of device paths or empty
|
|
||||||
:param major_minors: Array of structures (major,minor)
|
|
||||||
:param tmo: Timeout for operation
|
|
||||||
:param scan_options: Additional options to pvscan
|
|
||||||
:param cb: Not visible in API (used for async. callback)
|
|
||||||
:param cbe: Not visible in API (used for async. error callback)
|
|
||||||
:return: '/' if operation done, else job path
|
|
||||||
"""
|
|
||||||
for d in device_paths:
|
|
||||||
utils.validate_device_path(MANAGER_INTERFACE, d)
|
|
||||||
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, Manager._pv_scan,
|
|
||||||
(activate, cache, device_paths, major_minors,
|
|
||||||
scan_options), cb, cbe, False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def lvm_id(self):
|
|
||||||
"""
|
|
||||||
Intended to be overridden by classes that inherit
|
|
||||||
"""
|
|
||||||
return str(id(self))
|
|
||||||
|
|
||||||
@property
|
|
||||||
def Uuid(self):
|
|
||||||
"""
|
|
||||||
Intended to be overridden by classes that inherit
|
|
||||||
"""
|
|
||||||
import uuid
|
|
||||||
return uuid.uuid1()
|
|
||||||
@@ -1,308 +0,0 @@
|
|||||||
# 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/>.
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import threading
|
|
||||||
import traceback
|
|
||||||
import dbus
|
|
||||||
import os
|
|
||||||
from . import cfg
|
|
||||||
from .utils import log_debug
|
|
||||||
from .automatedproperties import AutomatedProperties
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyPep8Naming
|
|
||||||
class ObjectManager(AutomatedProperties):
|
|
||||||
"""
|
|
||||||
Implements the org.freedesktop.DBus.ObjectManager interface
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, object_path, interface):
|
|
||||||
super(ObjectManager, self).__init__(object_path, interface)
|
|
||||||
self.set_interface(interface)
|
|
||||||
self._ap_o_path = object_path
|
|
||||||
self._objects = {}
|
|
||||||
self._id_to_object_path = {}
|
|
||||||
self.rlock = threading.RLock()
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface="org.freedesktop.DBus.ObjectManager",
|
|
||||||
out_signature='a{oa{sa{sv}}}')
|
|
||||||
def GetManagedObjects(self):
|
|
||||||
with self.rlock:
|
|
||||||
rc = {}
|
|
||||||
try:
|
|
||||||
for k, v in list(self._objects.items()):
|
|
||||||
path, props = v[0].emit_data()
|
|
||||||
rc[path] = props
|
|
||||||
except Exception:
|
|
||||||
traceback.print_exc(file=sys.stdout)
|
|
||||||
sys.exit(1)
|
|
||||||
return rc
|
|
||||||
|
|
||||||
def locked(self):
|
|
||||||
"""
|
|
||||||
If some external code need to run across a number of different
|
|
||||||
calls into ObjectManager while blocking others they can use this method
|
|
||||||
to lock others out.
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
return ObjectManagerLock(self.rlock)
|
|
||||||
|
|
||||||
@dbus.service.signal(
|
|
||||||
dbus_interface="org.freedesktop.DBus.ObjectManager",
|
|
||||||
signature='oa{sa{sv}}')
|
|
||||||
def InterfacesAdded(self, object_path, int_name_prop_dict):
|
|
||||||
log_debug(
|
|
||||||
('SIGNAL: InterfacesAdded(%s, %s)' %
|
|
||||||
(str(object_path), str(int_name_prop_dict))))
|
|
||||||
|
|
||||||
@dbus.service.signal(
|
|
||||||
dbus_interface="org.freedesktop.DBus.ObjectManager",
|
|
||||||
signature='oas')
|
|
||||||
def InterfacesRemoved(self, object_path, interface_list):
|
|
||||||
log_debug(('SIGNAL: InterfacesRemoved(%s, %s)' %
|
|
||||||
(str(object_path), str(interface_list))))
|
|
||||||
|
|
||||||
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 user name for the asset
|
|
||||||
:param uuid: The uuid for the asset
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
# Note: Only called internally, lock implied
|
|
||||||
|
|
||||||
# We could have a temp entry from the forward creation of a path
|
|
||||||
self._lookup_remove(path)
|
|
||||||
|
|
||||||
self._objects[path] = (obj, lvm_id, uuid)
|
|
||||||
self._id_to_object_path[lvm_id] = path
|
|
||||||
|
|
||||||
if uuid:
|
|
||||||
self._id_to_object_path[uuid] = path
|
|
||||||
|
|
||||||
def _lookup_remove(self, obj_path):
|
|
||||||
# Note: Only called internally, lock implied
|
|
||||||
if obj_path in self._objects:
|
|
||||||
(obj, lvm_id, uuid) = self._objects[obj_path]
|
|
||||||
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):
|
|
||||||
with self.rlock:
|
|
||||||
obj_path = dbus_obj.dbus_object_path()
|
|
||||||
self._lookup_remove(obj_path)
|
|
||||||
self._lookup_add(
|
|
||||||
dbus_obj, obj_path,
|
|
||||||
new_lvm_id, new_uuid)
|
|
||||||
|
|
||||||
def object_paths_by_type(self, o_type):
|
|
||||||
with self.rlock:
|
|
||||||
rc = {}
|
|
||||||
|
|
||||||
for k, v in list(self._objects.items()):
|
|
||||||
if isinstance(v[0], o_type):
|
|
||||||
rc[k] = True
|
|
||||||
return rc
|
|
||||||
|
|
||||||
def register_object(self, dbus_object, emit_signal=False):
|
|
||||||
"""
|
|
||||||
Given a dbus object add it to the collection
|
|
||||||
:param dbus_object: Dbus object to register
|
|
||||||
:param emit_signal: If true emit a signal for interfaces added
|
|
||||||
"""
|
|
||||||
with self.rlock:
|
|
||||||
path, props = dbus_object.emit_data()
|
|
||||||
|
|
||||||
# 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
|
|
||||||
self._lookup_add(dbus_object, path, dbus_object.lvm_id,
|
|
||||||
dbus_object.Uuid)
|
|
||||||
|
|
||||||
if emit_signal:
|
|
||||||
self.InterfacesAdded(path, props)
|
|
||||||
|
|
||||||
def remove_object(self, dbus_object, emit_signal=False):
|
|
||||||
"""
|
|
||||||
Given a dbus object, remove it from the collection and remove it
|
|
||||||
from the dbus framework as well
|
|
||||||
:param dbus_object: Dbus object to remove
|
|
||||||
:param emit_signal: If true emit the interfaces removed signal
|
|
||||||
"""
|
|
||||||
with self.rlock:
|
|
||||||
# Store off the object path and the interface first
|
|
||||||
path = dbus_object.dbus_object_path()
|
|
||||||
interfaces = dbus_object.interface()
|
|
||||||
|
|
||||||
# print 'UN-Registering object path %s for %s' % \
|
|
||||||
# (path, dbus_object.lvm_id)
|
|
||||||
|
|
||||||
self._lookup_remove(path)
|
|
||||||
|
|
||||||
# Remove from dbus library
|
|
||||||
dbus_object.remove_from_connection(cfg.bus, path)
|
|
||||||
|
|
||||||
# Optionally emit a signal
|
|
||||||
if emit_signal:
|
|
||||||
self.InterfacesRemoved(path, interfaces)
|
|
||||||
|
|
||||||
def get_object_by_path(self, path):
|
|
||||||
"""
|
|
||||||
Given a dbus path return the object registered for it
|
|
||||||
:param path: The dbus path
|
|
||||||
:return: The object
|
|
||||||
"""
|
|
||||||
with self.rlock:
|
|
||||||
if path in self._objects:
|
|
||||||
return self._objects[path][0]
|
|
||||||
return None
|
|
||||||
|
|
||||||
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, None, False))
|
|
||||||
|
|
||||||
def get_object_by_lvm_id(self, lvm_id):
|
|
||||||
"""
|
|
||||||
Given an lvm identifier, return the object registered for it
|
|
||||||
:param lvm_id: The lvm identifier
|
|
||||||
"""
|
|
||||||
with self.rlock:
|
|
||||||
if lvm_id in self._id_to_object_path:
|
|
||||||
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):
|
|
||||||
"""
|
|
||||||
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
|
|
||||||
:return: None
|
|
||||||
"""
|
|
||||||
# This gets called when we found an object based on lvm_id, ensure
|
|
||||||
# uuid is correct too, as they can change
|
|
||||||
if lvm_id != uuid:
|
|
||||||
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 _return_lookup(self, uuid, lvm_identifier):
|
|
||||||
"""
|
|
||||||
We found an identifier, so lets return the path to the found object
|
|
||||||
:param uuid: The lvm uuid
|
|
||||||
:param lvm_identifier: The lvm_id used to find object
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
path = self._id_to_object_path[lvm_identifier]
|
|
||||||
self._uuid_verify(path, uuid, lvm_identifier)
|
|
||||||
return path
|
|
||||||
|
|
||||||
def get_object_path_by_uuid_lvm_id(self, uuid, lvm_id, path_create=None,
|
|
||||||
gen_new=True):
|
|
||||||
"""
|
|
||||||
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 gen_new:
|
|
||||||
assert path_create
|
|
||||||
|
|
||||||
path = None
|
|
||||||
|
|
||||||
if lvm_id in self._id_to_object_path:
|
|
||||||
self._return_lookup(uuid, lvm_id)
|
|
||||||
|
|
||||||
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:
|
|
||||||
self._return_lookup(uuid, int_lvm_id)
|
|
||||||
elif lvm_id.startswith('/'):
|
|
||||||
# We could have a pv device path lookup that failed,
|
|
||||||
# lets try canonical form and try again.
|
|
||||||
canonical = os.path.realpath(lvm_id)
|
|
||||||
if canonical in self._id_to_object_path:
|
|
||||||
self._return_lookup(uuid, canonical)
|
|
||||||
|
|
||||||
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:
|
|
||||||
if gen_new:
|
|
||||||
path = path_create()
|
|
||||||
self._lookup_add(None, path, lvm_id, uuid)
|
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
|
|
||||||
class ObjectManagerLock(object):
|
|
||||||
"""
|
|
||||||
The sole purpose of this class is to allow other code the ability to
|
|
||||||
lock the object manager using a `with` statement, eg.
|
|
||||||
|
|
||||||
with cfg.om.locked():
|
|
||||||
# Do stuff with object manager
|
|
||||||
|
|
||||||
This will ensure that the lock is always released (assuming this is done
|
|
||||||
correctly)
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, recursive_lock):
|
|
||||||
self._lock = recursive_lock
|
|
||||||
|
|
||||||
def __enter__(self):
|
|
||||||
# Acquire lock
|
|
||||||
self._lock.acquire()
|
|
||||||
|
|
||||||
# noinspection PyUnusedLocal
|
|
||||||
def __exit__(self, e_type, e_value, e_traceback):
|
|
||||||
# Release lock
|
|
||||||
self._lock.release()
|
|
||||||
self._lock = None
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
# 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/>.
|
|
||||||
|
|
||||||
LVM_BINARY = "@LVM_PATH@"
|
|
||||||
@@ -1,282 +0,0 @@
|
|||||||
# 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/>.
|
|
||||||
|
|
||||||
from .automatedproperties import AutomatedProperties
|
|
||||||
from . import utils
|
|
||||||
from . import cfg
|
|
||||||
import dbus
|
|
||||||
from .cfg import PV_INTERFACE
|
|
||||||
from . import cmdhandler
|
|
||||||
from .utils import vg_obj_path_generate, n, pv_obj_path_generate, \
|
|
||||||
lv_object_path_method
|
|
||||||
from .loader import common
|
|
||||||
from .request import RequestEntry
|
|
||||||
from .state import State
|
|
||||||
from .utils import round_size
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyUnusedLocal
|
|
||||||
def pvs_state_retrieve(selection, cache_refresh=True):
|
|
||||||
rc = []
|
|
||||||
|
|
||||||
if cache_refresh:
|
|
||||||
cfg.db.refresh()
|
|
||||||
|
|
||||||
for p in cfg.db.fetch_pvs(selection):
|
|
||||||
rc.append(
|
|
||||||
PvState(
|
|
||||||
p["pv_name"], p["pv_uuid"], p["pv_name"],
|
|
||||||
p["pv_fmt"], n(p["pv_size"]), n(p["pv_free"]),
|
|
||||||
n(p["pv_used"]), n(p["dev_size"]), n(p["pv_mda_size"]),
|
|
||||||
n(p["pv_mda_free"]), int(p["pv_ba_start"]),
|
|
||||||
n(p["pv_ba_size"]), n(p["pe_start"]),
|
|
||||||
int(p["pv_pe_count"]), int(p["pv_pe_alloc_count"]),
|
|
||||||
p["pv_attr"], p["pv_tags"], p["vg_name"], p["vg_uuid"]))
|
|
||||||
return rc
|
|
||||||
|
|
||||||
|
|
||||||
def load_pvs(device=None, object_path=None, refresh=False, emit_signal=False,
|
|
||||||
cache_refresh=True):
|
|
||||||
return common(
|
|
||||||
pvs_state_retrieve, (Pv,), device, object_path, refresh,
|
|
||||||
emit_signal, cache_refresh)
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyUnresolvedReferences
|
|
||||||
class PvState(State):
|
|
||||||
@property
|
|
||||||
def lvm_id(self):
|
|
||||||
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)):
|
|
||||||
lv_uuid, lv_name, meta, segs = lv
|
|
||||||
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_uuid, full_name, path_create)
|
|
||||||
|
|
||||||
rc.append((lv_path, segs))
|
|
||||||
return dbus.Array(rc, signature="(oa(tts))")
|
|
||||||
|
|
||||||
# noinspection PyUnusedLocal,PyPep8Naming
|
|
||||||
def __init__(self, lvm_path, Uuid, Name,
|
|
||||||
Fmt, SizeBytes, FreeBytes, UsedBytes, DevSizeBytes,
|
|
||||||
MdaSizeBytes, MdaFreeBytes, BaStart, BaSizeBytes,
|
|
||||||
PeStart, PeCount, PeAllocCount, attr, Tags, vg_name,
|
|
||||||
vg_uuid):
|
|
||||||
utils.init_class_from_arguments(self)
|
|
||||||
self.pe_segments = cfg.db.pv_pe_segments(Uuid)
|
|
||||||
|
|
||||||
self.lv = self._lv_object_list(vg_name)
|
|
||||||
|
|
||||||
if vg_name:
|
|
||||||
self.vg_path = cfg.om.get_object_path_by_uuid_lvm_id(
|
|
||||||
vg_uuid, vg_name, vg_obj_path_generate)
|
|
||||||
else:
|
|
||||||
self.vg_path = '/'
|
|
||||||
|
|
||||||
def identifiers(self):
|
|
||||||
return (self.Uuid, self.lvm_path)
|
|
||||||
|
|
||||||
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)
|
|
||||||
return Pv(path, self)
|
|
||||||
|
|
||||||
# noinspection PyMethodMayBeStatic
|
|
||||||
def creation_signature(self):
|
|
||||||
return (Pv, pv_obj_path_generate)
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyPep8Naming
|
|
||||||
@utils.dbus_property(PV_INTERFACE, 'Uuid', 's') # PV UUID/pv_uuid
|
|
||||||
@utils.dbus_property(PV_INTERFACE, 'Name', 's') # PV/pv_name
|
|
||||||
@utils.dbus_property(PV_INTERFACE, 'Fmt', 's') # Fmt/pv_fmt
|
|
||||||
@utils.dbus_property(PV_INTERFACE, 'SizeBytes', 't') # PSize/pv_size
|
|
||||||
@utils.dbus_property(PV_INTERFACE, 'FreeBytes', 't') # PFree/pv_free
|
|
||||||
@utils.dbus_property(PV_INTERFACE, 'UsedBytes', 't') # Used/pv_used
|
|
||||||
@utils.dbus_property(PV_INTERFACE, 'DevSizeBytes', 't') # DevSize/dev_size
|
|
||||||
@utils.dbus_property(PV_INTERFACE, 'MdaSizeBytes', 't') # PMdaSize/pv_mda_size
|
|
||||||
@utils.dbus_property(PV_INTERFACE, 'MdaFreeBytes', 't') # PMdaFree/pv_mda_free
|
|
||||||
@utils.dbus_property(PV_INTERFACE, 'BaStart', 't') # BA start/pv_ba_start
|
|
||||||
@utils.dbus_property(PV_INTERFACE, 'BaSizeBytes', 't') # BA size/pv_ba_size
|
|
||||||
@utils.dbus_property(PV_INTERFACE, 'PeStart', 't') # 1st PE/pe_start
|
|
||||||
@utils.dbus_property(PV_INTERFACE, 'PeCount', 't') # PE/pv_pe_count
|
|
||||||
@utils.dbus_property(PV_INTERFACE, 'PeAllocCount', 't') # PE Allocation count
|
|
||||||
class Pv(AutomatedProperties):
|
|
||||||
# For properties that we need custom handlers we need these, otherwise
|
|
||||||
# we won't get our introspection data
|
|
||||||
_Tags_meta = ("as", PV_INTERFACE)
|
|
||||||
_PeSegments_meta = ("a(tt)", PV_INTERFACE)
|
|
||||||
_Exportable_meta = ("b", PV_INTERFACE)
|
|
||||||
_Allocatable_meta = ("b", PV_INTERFACE)
|
|
||||||
_Missing_meta = ("b", PV_INTERFACE)
|
|
||||||
_Lv_meta = ("a(oa(tts))", PV_INTERFACE)
|
|
||||||
_Vg_meta = ("o", PV_INTERFACE)
|
|
||||||
|
|
||||||
# noinspection PyUnusedLocal,PyPep8Naming
|
|
||||||
def __init__(self, object_path, state_obj):
|
|
||||||
super(Pv, self).__init__(object_path, pvs_state_retrieve)
|
|
||||||
self.set_interface(PV_INTERFACE)
|
|
||||||
self.state = state_obj
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
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
|
|
||||||
dbo = cfg.om.get_object_by_uuid_lvm_id(pv_uuid, pv_name)
|
|
||||||
|
|
||||||
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 '/'
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=PV_INTERFACE,
|
|
||||||
in_signature='ia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def Remove(self, tmo, remove_options, cb, cbe):
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, Pv._remove,
|
|
||||||
(self.Uuid, self.lvm_id, remove_options),
|
|
||||||
cb, cbe, return_tuple=False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _resize(pv_uuid, pv_name, new_size_bytes, resize_options):
|
|
||||||
# Make sure we have a dbus object representing it
|
|
||||||
dbo = cfg.om.get_object_by_uuid_lvm_id(pv_uuid, pv_name)
|
|
||||||
|
|
||||||
if dbo:
|
|
||||||
rc, out, err = cmdhandler.pv_resize(pv_name, new_size_bytes,
|
|
||||||
resize_options)
|
|
||||||
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(
|
|
||||||
dbus_interface=PV_INTERFACE,
|
|
||||||
in_signature='tia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def ReSize(self, new_size_bytes, tmo, resize_options, cb, cbe):
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, Pv._resize,
|
|
||||||
(self.Uuid, self.lvm_id, round_size(new_size_bytes),
|
|
||||||
resize_options), cb, cbe, False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _allocation_enabled(pv_uuid, pv_name, yes_no, allocation_options):
|
|
||||||
# Make sure we have a dbus object representing it
|
|
||||||
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(
|
|
||||||
dbus_interface=PV_INTERFACE,
|
|
||||||
in_signature='bia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def AllocationEnabled(self, yes, tmo, allocation_options, cb, cbe):
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, Pv._allocation_enabled,
|
|
||||||
(self.Uuid, self.lvm_id,
|
|
||||||
yes, allocation_options),
|
|
||||||
cb, cbe, False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def Tags(self):
|
|
||||||
return utils.parse_tags(self.state.Tags)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def PeSegments(self):
|
|
||||||
if len(self.state.pe_segments):
|
|
||||||
return self.state.pe_segments
|
|
||||||
return dbus.Array([], '(tt)')
|
|
||||||
|
|
||||||
@property
|
|
||||||
def Exportable(self):
|
|
||||||
if self.state.attr[1] == 'x':
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
@property
|
|
||||||
def Allocatable(self):
|
|
||||||
if self.state.attr[0] == 'a':
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
@property
|
|
||||||
def Missing(self):
|
|
||||||
if self.state.attr[2] == 'm':
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def object_path(self):
|
|
||||||
return self._object_path
|
|
||||||
|
|
||||||
@property
|
|
||||||
def lvm_id(self):
|
|
||||||
return self.state.lvm_id
|
|
||||||
|
|
||||||
@property
|
|
||||||
def identifiers(self):
|
|
||||||
return self.state.identifiers()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def Lv(self):
|
|
||||||
return self.state.lv
|
|
||||||
|
|
||||||
@property
|
|
||||||
def Vg(self):
|
|
||||||
return self.state.vg_path
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,151 +0,0 @@
|
|||||||
# 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/>.
|
|
||||||
|
|
||||||
import threading
|
|
||||||
# noinspection PyUnresolvedReferences
|
|
||||||
from gi.repository import GLib
|
|
||||||
from .job import Job
|
|
||||||
from . import cfg
|
|
||||||
import traceback
|
|
||||||
from .utils import log_error
|
|
||||||
|
|
||||||
|
|
||||||
class RequestEntry(object):
|
|
||||||
def __init__(self, tmo, method, arguments, cb, cb_error,
|
|
||||||
return_tuple=True, job_state=None):
|
|
||||||
self.tmo = tmo
|
|
||||||
self.method = method
|
|
||||||
self.arguments = arguments
|
|
||||||
self.cb = cb
|
|
||||||
self.cb_error = cb_error
|
|
||||||
|
|
||||||
self.timer_id = -1
|
|
||||||
self.lock = threading.RLock()
|
|
||||||
self.done = False
|
|
||||||
self._result = None
|
|
||||||
self._job = None
|
|
||||||
self._rc = 0
|
|
||||||
self._rc_error = None
|
|
||||||
self._return_tuple = return_tuple
|
|
||||||
self._job_state = job_state
|
|
||||||
|
|
||||||
if self.tmo < 0:
|
|
||||||
# Client is willing to block forever
|
|
||||||
pass
|
|
||||||
elif tmo == 0:
|
|
||||||
self._return_job()
|
|
||||||
else:
|
|
||||||
self.timer_id = GLib.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: Nothing
|
|
||||||
"""
|
|
||||||
r.timer_expired()
|
|
||||||
|
|
||||||
def _return_job(self):
|
|
||||||
self._job = Job(self, self._job_state)
|
|
||||||
cfg.om.register_object(self._job, True)
|
|
||||||
if self._return_tuple:
|
|
||||||
self.cb(('/', self._job.dbus_object_path()))
|
|
||||||
else:
|
|
||||||
self.cb(self._job.dbus_object_path())
|
|
||||||
|
|
||||||
def run_cmd(self):
|
|
||||||
try:
|
|
||||||
result = self.method(*self.arguments)
|
|
||||||
self.register_result(result)
|
|
||||||
except Exception as e:
|
|
||||||
# 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)
|
|
||||||
|
|
||||||
def is_done(self):
|
|
||||||
with self.lock:
|
|
||||||
rc = self.done
|
|
||||||
return rc
|
|
||||||
|
|
||||||
def get_errors(self):
|
|
||||||
with self.lock:
|
|
||||||
return (self._rc, self._rc_error)
|
|
||||||
|
|
||||||
def result(self):
|
|
||||||
with self.lock:
|
|
||||||
if self.done:
|
|
||||||
return self._result
|
|
||||||
return '/'
|
|
||||||
|
|
||||||
def _reg_ending(self, result, error_rc=0, error_msg=None,
|
|
||||||
error_exception=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)
|
|
||||||
|
|
||||||
self._result = result
|
|
||||||
self._rc = error_rc
|
|
||||||
self._rc_error = error_msg
|
|
||||||
|
|
||||||
if not self._job:
|
|
||||||
# We finished and there is no job, so return result or error
|
|
||||||
# now!
|
|
||||||
# Note: If we don't have a valid cb or cbe, this indicates a
|
|
||||||
# request that doesn't need a response as we already returned
|
|
||||||
# one before the request was processed.
|
|
||||||
if error_rc == 0:
|
|
||||||
if self.cb:
|
|
||||||
if self._return_tuple:
|
|
||||||
self.cb((result, '/'))
|
|
||||||
else:
|
|
||||||
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)
|
|
||||||
|
|
||||||
self.cb_error(error_exception)
|
|
||||||
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(None, error_rc, error_message, error_exception)
|
|
||||||
|
|
||||||
def register_result(self, result):
|
|
||||||
self._reg_ending(result)
|
|
||||||
|
|
||||||
def timer_expired(self):
|
|
||||||
with self.lock:
|
|
||||||
# Set the timer back to -1 as we will get a warning if we try
|
|
||||||
# to remove a timer that doesn't exist
|
|
||||||
self.timer_id = -1
|
|
||||||
if not self.done:
|
|
||||||
# Create dbus job object and return path to caller
|
|
||||||
self._return_job()
|
|
||||||
else:
|
|
||||||
# The job is done, we have nothing to do
|
|
||||||
pass
|
|
||||||
|
|
||||||
return False
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
# 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/>.
|
|
||||||
|
|
||||||
from abc import ABCMeta, abstractmethod
|
|
||||||
|
|
||||||
|
|
||||||
class State(object, metaclass=ABCMeta):
|
|
||||||
@abstractmethod
|
|
||||||
def lvm_id(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def identifiers(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def create_dbus_object(self, path):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return '*****\n' + str(self.__dict__) + '\n******\n'
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
# 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/>.
|
|
||||||
|
|
||||||
import pyudev
|
|
||||||
from .refresh import event_add
|
|
||||||
from . import cfg
|
|
||||||
|
|
||||||
observer = None
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyUnusedLocal
|
|
||||||
def filter_event(action, device):
|
|
||||||
# Filter for events of interest and add a request object to be processed
|
|
||||||
# when appropriate.
|
|
||||||
refresh = False
|
|
||||||
|
|
||||||
if '.ID_FS_TYPE_NEW' in device:
|
|
||||||
fs_type_new = device['.ID_FS_TYPE_NEW']
|
|
||||||
|
|
||||||
if 'LVM' in fs_type_new:
|
|
||||||
refresh = True
|
|
||||||
elif fs_type_new == '':
|
|
||||||
# Check to see if the device was one we knew about
|
|
||||||
if 'DEVNAME' in device:
|
|
||||||
found = cfg.om.get_object_by_lvm_id(device['DEVNAME'])
|
|
||||||
if found:
|
|
||||||
refresh = True
|
|
||||||
|
|
||||||
if 'DM_LV_NAME' in device:
|
|
||||||
refresh = True
|
|
||||||
|
|
||||||
if refresh:
|
|
||||||
event_add(('udev',))
|
|
||||||
|
|
||||||
|
|
||||||
def add():
|
|
||||||
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():
|
|
||||||
global observer
|
|
||||||
observer.stop()
|
|
||||||
observer = None
|
|
||||||
@@ -1,484 +0,0 @@
|
|||||||
# 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/>.
|
|
||||||
|
|
||||||
import xml.etree.ElementTree as Et
|
|
||||||
import sys
|
|
||||||
import inspect
|
|
||||||
import ctypes
|
|
||||||
import os
|
|
||||||
import string
|
|
||||||
|
|
||||||
import dbus
|
|
||||||
import dbus.service
|
|
||||||
import dbus.mainloop.glib
|
|
||||||
|
|
||||||
try:
|
|
||||||
from . import cfg
|
|
||||||
except SystemError:
|
|
||||||
import cfg
|
|
||||||
|
|
||||||
STDOUT_TTY = os.isatty(sys.stdout.fileno())
|
|
||||||
|
|
||||||
|
|
||||||
def rtype(dbus_type):
|
|
||||||
"""
|
|
||||||
Decorator making sure that the decorated function returns a value of
|
|
||||||
specified type.
|
|
||||||
:param dbus_type: The specific dbus type to return value as
|
|
||||||
"""
|
|
||||||
|
|
||||||
def decorator(fn):
|
|
||||||
def decorated(*args, **kwargs):
|
|
||||||
return dbus_type(fn(*args, **kwargs))
|
|
||||||
|
|
||||||
return decorated
|
|
||||||
|
|
||||||
return decorator
|
|
||||||
|
|
||||||
|
|
||||||
# Field is expected to be a number, handle the corner cases when parsing
|
|
||||||
@rtype(dbus.UInt64)
|
|
||||||
def n(v):
|
|
||||||
if not v:
|
|
||||||
return 0
|
|
||||||
return int(float(v))
|
|
||||||
|
|
||||||
|
|
||||||
@rtype(dbus.UInt32)
|
|
||||||
def n32(v):
|
|
||||||
if not v:
|
|
||||||
return 0
|
|
||||||
return int(float(v))
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyProtectedMember
|
|
||||||
def init_class_from_arguments(obj_instance):
|
|
||||||
for k, v in list(sys._getframe(1).f_locals.items()):
|
|
||||||
if k != 'self':
|
|
||||||
nt = k
|
|
||||||
|
|
||||||
# If the current attribute has a value, but the incoming does
|
|
||||||
# not, don't overwrite it. Otherwise the default values on the
|
|
||||||
# property decorator don't work as expected.
|
|
||||||
cur = getattr(obj_instance, nt, v)
|
|
||||||
|
|
||||||
# print 'Init class %s = %s' % (nt, str(v))
|
|
||||||
if not (cur and len(str(cur)) and (v is None or len(str(v))) == 0):
|
|
||||||
setattr(obj_instance, nt, v)
|
|
||||||
|
|
||||||
|
|
||||||
def get_properties(f):
|
|
||||||
"""
|
|
||||||
Walks through an object instance or it's parent class(es) and determines
|
|
||||||
which attributes are properties and if they were created to be used for
|
|
||||||
dbus.
|
|
||||||
:param f: Object to inspect
|
|
||||||
:return: A dictionary of tuples with each tuple being:
|
|
||||||
0 = An array of dicts with the keys being: p_t, p_name,
|
|
||||||
p_access(type, name, access)
|
|
||||||
1 = Hash of property names and current value
|
|
||||||
"""
|
|
||||||
interfaces = dict()
|
|
||||||
|
|
||||||
for c in inspect.getmro(f.__class__):
|
|
||||||
|
|
||||||
h = vars(c)
|
|
||||||
for p, value in h.items():
|
|
||||||
if isinstance(value, property):
|
|
||||||
# We found a property, see if it has a metadata type
|
|
||||||
key = attribute_type_name(p)
|
|
||||||
if key in h:
|
|
||||||
interface = h[key][1]
|
|
||||||
|
|
||||||
if interface not in interfaces:
|
|
||||||
interfaces[interface] = ([], {})
|
|
||||||
|
|
||||||
access = ''
|
|
||||||
if getattr(f.__class__, p).fget:
|
|
||||||
access += 'read'
|
|
||||||
if getattr(f.__class__, p).fset:
|
|
||||||
access += 'write'
|
|
||||||
|
|
||||||
interfaces[interface][0].append(
|
|
||||||
dict(
|
|
||||||
p_t=getattr(f, key)[0],
|
|
||||||
p_name=p,
|
|
||||||
p_access=access))
|
|
||||||
|
|
||||||
interfaces[interface][1][p] = getattr(f, p)
|
|
||||||
|
|
||||||
return interfaces
|
|
||||||
|
|
||||||
|
|
||||||
def get_object_property_diff(o_prop, n_prop):
|
|
||||||
"""
|
|
||||||
Walk through each object properties and report what has changed and with
|
|
||||||
the new values
|
|
||||||
:param o_prop: Old keys/values
|
|
||||||
:param n_prop: New keys/values
|
|
||||||
:return: hash of properties that have changed and their new value
|
|
||||||
"""
|
|
||||||
rc = {}
|
|
||||||
|
|
||||||
for intf_k, intf_v in o_prop.items():
|
|
||||||
for k, v in list(intf_v[1].items()):
|
|
||||||
# print('Comparing %s:%s to %s:%s' %
|
|
||||||
# (k, o_prop[intf_k][1][k], k, str(n_prop[intf_k][1][k])))
|
|
||||||
if o_prop[intf_k][1][k] != n_prop[intf_k][1][k]:
|
|
||||||
new_value = n_prop[intf_k][1][k]
|
|
||||||
|
|
||||||
if intf_k not in rc:
|
|
||||||
rc[intf_k] = dict()
|
|
||||||
|
|
||||||
rc[intf_k][k] = new_value
|
|
||||||
return rc
|
|
||||||
|
|
||||||
|
|
||||||
def add_properties(xml, interface, props):
|
|
||||||
"""
|
|
||||||
Given xml that describes the interface, add property values to the XML
|
|
||||||
for the specified interface.
|
|
||||||
:param xml: XML to edit
|
|
||||||
:param interface: Interface to add the properties too
|
|
||||||
:param props: Output from get_properties
|
|
||||||
:return: updated XML string
|
|
||||||
"""
|
|
||||||
root = Et.fromstring(xml)
|
|
||||||
|
|
||||||
if props:
|
|
||||||
|
|
||||||
for c in root:
|
|
||||||
# print c.attrib['name']
|
|
||||||
if c.attrib['name'] == interface:
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
def attribute_type_name(name):
|
|
||||||
"""
|
|
||||||
Given the property name, return string of the attribute type
|
|
||||||
:param name:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
return "_%s_meta" % name
|
|
||||||
|
|
||||||
|
|
||||||
_type_map = dict(
|
|
||||||
s=dbus.String,
|
|
||||||
o=dbus.ObjectPath,
|
|
||||||
t=dbus.UInt64,
|
|
||||||
x=dbus.Int64,
|
|
||||||
u=dbus.UInt32,
|
|
||||||
i=dbus.Int32,
|
|
||||||
n=dbus.Int16,
|
|
||||||
q=dbus.UInt16,
|
|
||||||
d=dbus.Double,
|
|
||||||
y=dbus.Byte,
|
|
||||||
b=dbus.Boolean)
|
|
||||||
|
|
||||||
|
|
||||||
def _pass_through(v):
|
|
||||||
"""
|
|
||||||
If we have something which is not a simple type we return the original
|
|
||||||
value un-wrapped.
|
|
||||||
:param v:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
return v
|
|
||||||
|
|
||||||
|
|
||||||
def _dbus_type(t, value):
|
|
||||||
return _type_map.get(t, _pass_through)(value)
|
|
||||||
|
|
||||||
|
|
||||||
def dbus_property(interface_name, name, dbus_type, doc=None):
|
|
||||||
"""
|
|
||||||
Creates the get/set properties for the given name. It assumes that the
|
|
||||||
actual attribute is '_' + name and the attribute metadata is stuffed in
|
|
||||||
_name_type.
|
|
||||||
|
|
||||||
There is probably a better way todo this.
|
|
||||||
:param interface_name: Dbus interface this property is associated with
|
|
||||||
:param name: Name of property
|
|
||||||
:param dbus_type: dbus string type eg. s,t,i,x
|
|
||||||
:param doc: Python __doc__ for the property
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
attribute_name = '_' + name
|
|
||||||
|
|
||||||
def getter(self):
|
|
||||||
t = getattr(self, attribute_name + '_meta')[0]
|
|
||||||
return _dbus_type(t, getattr(self.state, attribute_name[1:]))
|
|
||||||
|
|
||||||
prop = property(getter, None, None, doc)
|
|
||||||
|
|
||||||
def decorator(cls):
|
|
||||||
setattr(cls, attribute_name + '_meta', (dbus_type, interface_name))
|
|
||||||
setattr(cls, name, prop)
|
|
||||||
return cls
|
|
||||||
|
|
||||||
return decorator
|
|
||||||
|
|
||||||
|
|
||||||
def parse_tags(tags):
|
|
||||||
if len(tags):
|
|
||||||
if ',' in tags:
|
|
||||||
return tags.split(',')
|
|
||||||
return sorted([tags])
|
|
||||||
return dbus.Array([], signature='s')
|
|
||||||
|
|
||||||
|
|
||||||
def _common_log(msg, *attributes):
|
|
||||||
cfg.stdout_lock.acquire()
|
|
||||||
tid = ctypes.CDLL('libc.so.6').syscall(186)
|
|
||||||
|
|
||||||
msg = "%d:%d - %s" % (os.getpid(), tid, msg)
|
|
||||||
|
|
||||||
if STDOUT_TTY and attributes:
|
|
||||||
print(color(msg, *attributes))
|
|
||||||
else:
|
|
||||||
print(msg)
|
|
||||||
|
|
||||||
cfg.stdout_lock.release()
|
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
|
|
||||||
# Serializes access to stdout to prevent interleaved output
|
|
||||||
# @param msg Message to output to stdout
|
|
||||||
# @return None
|
|
||||||
def log_debug(msg, *attributes):
|
|
||||||
if cfg.DEBUG:
|
|
||||||
_common_log(msg, *attributes)
|
|
||||||
|
|
||||||
|
|
||||||
def log_error(msg, *attributes):
|
|
||||||
_common_log(msg, *attributes)
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyUnusedLocal
|
|
||||||
def handler(signum, frame):
|
|
||||||
cfg.run.value = 0
|
|
||||||
log_debug('Signal handler called with signal %d' % signum)
|
|
||||||
if cfg.loop is not None:
|
|
||||||
cfg.loop.quit()
|
|
||||||
|
|
||||||
|
|
||||||
def pv_obj_path_generate():
|
|
||||||
return cfg.PV_OBJ_PATH + "/%d" % next(cfg.pv_id)
|
|
||||||
|
|
||||||
|
|
||||||
def vg_obj_path_generate():
|
|
||||||
return cfg.VG_OBJ_PATH + "/%d" % next(cfg.vg_id)
|
|
||||||
|
|
||||||
|
|
||||||
def lv_object_path_method(name, meta):
|
|
||||||
if name[0] == '[':
|
|
||||||
return _hidden_lv_obj_path_generate
|
|
||||||
elif meta[0][0] == 't':
|
|
||||||
return _thin_pool_obj_path_generate
|
|
||||||
elif meta[0][0] == 'C' and 'pool' in meta[1]:
|
|
||||||
return _cache_pool_obj_path_generate
|
|
||||||
|
|
||||||
return _lv_obj_path_generate
|
|
||||||
|
|
||||||
|
|
||||||
# Note: None of the individual LV path generate functions should be called
|
|
||||||
# directly, they should only be dispatched through lv_object_path_method
|
|
||||||
|
|
||||||
def _lv_obj_path_generate():
|
|
||||||
return cfg.LV_OBJ_PATH + "/%d" % next(cfg.lv_id)
|
|
||||||
|
|
||||||
|
|
||||||
def _thin_pool_obj_path_generate():
|
|
||||||
return cfg.THIN_POOL_PATH + "/%d" % next(cfg.thin_id)
|
|
||||||
|
|
||||||
|
|
||||||
def _cache_pool_obj_path_generate():
|
|
||||||
return cfg.CACHE_POOL_PATH + "/%d" % next(cfg.cache_pool_id)
|
|
||||||
|
|
||||||
|
|
||||||
def _hidden_lv_obj_path_generate():
|
|
||||||
return cfg.HIDDEN_LV_PATH + "/%d" % next(cfg.hidden_lv)
|
|
||||||
|
|
||||||
|
|
||||||
def job_obj_path_generate():
|
|
||||||
return cfg.JOB_OBJ_PATH + "/%d" % next(cfg.job_id)
|
|
||||||
|
|
||||||
|
|
||||||
def color(text, *user_styles):
|
|
||||||
styles = {
|
|
||||||
# styles
|
|
||||||
'reset': '\033[0m',
|
|
||||||
'bold': '\033[01m',
|
|
||||||
'disabled': '\033[02m',
|
|
||||||
'underline': '\033[04m',
|
|
||||||
'reverse': '\033[07m',
|
|
||||||
'strike_through': '\033[09m',
|
|
||||||
'invisible': '\033[08m',
|
|
||||||
# text colors
|
|
||||||
'fg_black': '\033[30m',
|
|
||||||
'fg_red': '\033[31m',
|
|
||||||
'fg_green': '\033[32m',
|
|
||||||
'fg_orange': '\033[33m',
|
|
||||||
'fg_blue': '\033[34m',
|
|
||||||
'fg_purple': '\033[35m',
|
|
||||||
'fg_cyan': '\033[36m',
|
|
||||||
'fg_light_grey': '\033[37m',
|
|
||||||
'fg_dark_grey': '\033[90m',
|
|
||||||
'fg_light_red': '\033[91m',
|
|
||||||
'fg_light_green': '\033[92m',
|
|
||||||
'fg_yellow': '\033[93m',
|
|
||||||
'fg_light_blue': '\033[94m',
|
|
||||||
'fg_pink': '\033[95m',
|
|
||||||
'fg_light_cyan': '\033[96m',
|
|
||||||
# background colors
|
|
||||||
'bg_black': '\033[40m',
|
|
||||||
'bg_red': '\033[41m',
|
|
||||||
'bg_green': '\033[42m',
|
|
||||||
'bg_orange': '\033[43m',
|
|
||||||
'bg_blue': '\033[44m',
|
|
||||||
'bg_purple': '\033[45m',
|
|
||||||
'bg_cyan': '\033[46m',
|
|
||||||
'bg_light_grey': '\033[47m'
|
|
||||||
}
|
|
||||||
|
|
||||||
color_text = ''
|
|
||||||
for style in user_styles:
|
|
||||||
try:
|
|
||||||
color_text += styles[style]
|
|
||||||
except KeyError:
|
|
||||||
return 'def color: parameter {} does not exist'.format(style)
|
|
||||||
color_text += text
|
|
||||||
return '\033[0m{0}\033[0m'.format(color_text)
|
|
||||||
|
|
||||||
|
|
||||||
def pv_range_append(cmd, device, start, end):
|
|
||||||
if (start, end) == (0, 0):
|
|
||||||
cmd.append(device)
|
|
||||||
else:
|
|
||||||
if start != 0 and end == 0:
|
|
||||||
cmd.append("%s:%d-" % (device, start))
|
|
||||||
else:
|
|
||||||
cmd.append(
|
|
||||||
"%s:%d-%d" %
|
|
||||||
(device, start, end))
|
|
||||||
|
|
||||||
|
|
||||||
def pv_dest_ranges(cmd, pv_dest_range_list):
|
|
||||||
if len(pv_dest_range_list):
|
|
||||||
for i in pv_dest_range_list:
|
|
||||||
pv_range_append(cmd, *i)
|
|
||||||
|
|
||||||
|
|
||||||
def round_size(size_bytes):
|
|
||||||
bs = 512
|
|
||||||
remainder = size_bytes % bs
|
|
||||||
if not remainder:
|
|
||||||
return size_bytes
|
|
||||||
return size_bytes + bs - remainder
|
|
||||||
|
|
||||||
|
|
||||||
_ALLOWABLE_CH = string.ascii_letters + string.digits + '#+-.:=@_\/%'
|
|
||||||
_ALLOWABLE_CH_SET = set(_ALLOWABLE_CH)
|
|
||||||
|
|
||||||
_ALLOWABLE_VG_LV_CH = string.ascii_letters + string.digits + '.-_+'
|
|
||||||
_ALLOWABLE_VG_LV_CH_SET = set(_ALLOWABLE_VG_LV_CH)
|
|
||||||
_LV_NAME_RESERVED = ("_cdata", "_cmeta", "_corig", "_mimage", "_mlog",
|
|
||||||
"_pmspare", "_rimage", "_rmeta", "_tdata", "_tmeta", "_vorigin")
|
|
||||||
|
|
||||||
# Tags can have the characters, based on the code
|
|
||||||
# a-zA-Z0-9._-+/=!:&#
|
|
||||||
_ALLOWABLE_TAG_CH = string.ascii_letters + string.digits + "._-+/=!:&#"
|
|
||||||
_ALLOWABLE_TAG_CH_SET = set(_ALLOWABLE_TAG_CH)
|
|
||||||
|
|
||||||
|
|
||||||
def _allowable_tag(tag_name):
|
|
||||||
# LVM should impose a length restriction
|
|
||||||
return set(tag_name) <= _ALLOWABLE_TAG_CH_SET
|
|
||||||
|
|
||||||
|
|
||||||
def _allowable_vg_name(vg_name):
|
|
||||||
if vg_name is None:
|
|
||||||
raise ValueError("VG name is None or empty")
|
|
||||||
|
|
||||||
vg_len = len(vg_name)
|
|
||||||
if vg_len == 0 or vg_len > 127:
|
|
||||||
raise ValueError("VG name (%s) length (%d) not in the domain 1..127" %
|
|
||||||
(vg_name, vg_len))
|
|
||||||
|
|
||||||
if not set(vg_name) <= _ALLOWABLE_VG_LV_CH_SET:
|
|
||||||
raise ValueError("VG name (%s) contains invalid character, "
|
|
||||||
"allowable set(%s)" % (vg_name, _ALLOWABLE_VG_LV_CH))
|
|
||||||
|
|
||||||
if vg_name == "." or vg_name == "..":
|
|
||||||
raise ValueError('VG name (%s) cannot be "." or ".."' % (vg_name))
|
|
||||||
|
|
||||||
|
|
||||||
def _allowable_lv_name(vg_name, lv_name):
|
|
||||||
|
|
||||||
if lv_name is None:
|
|
||||||
raise ValueError("LV name is None or empty")
|
|
||||||
|
|
||||||
lv_len = len(lv_name)
|
|
||||||
|
|
||||||
# This length is derived from empirical testing
|
|
||||||
if lv_len == 0 or (len(vg_name) + lv_len) > 125:
|
|
||||||
raise ValueError("LV name (%s) length (%d) + VG name length "
|
|
||||||
"not in the domain 1..125" % (lv_name, lv_len))
|
|
||||||
|
|
||||||
if not set(lv_name) <= _ALLOWABLE_VG_LV_CH_SET:
|
|
||||||
raise ValueError("LV name (%s) contains invalid character, "
|
|
||||||
"allowable (%s)" % (lv_name, _ALLOWABLE_VG_LV_CH))
|
|
||||||
|
|
||||||
if any(x in lv_name for x in _LV_NAME_RESERVED):
|
|
||||||
raise ValueError("LV name (%s) contains a reserved word, "
|
|
||||||
"reserved set(%s)" % (lv_name, str(_LV_NAME_RESERVED)))
|
|
||||||
|
|
||||||
if lv_name.startswith("snapshot") or lv_name.startswith("pvmove"):
|
|
||||||
raise ValueError("LV name (%s) starts with a reserved word, "
|
|
||||||
"reserved set(%s)" % (lv_name, str(["snapshot", "pvmove"])))
|
|
||||||
|
|
||||||
if lv_name[0] == '-':
|
|
||||||
raise ValueError("LV name (%s) cannot start with a '-' "
|
|
||||||
"character" % lv_name)
|
|
||||||
|
|
||||||
|
|
||||||
def validate_device_path(interface, device):
|
|
||||||
if not set(device) <= _ALLOWABLE_CH_SET:
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
interface, 'Device path (%s) has invalid characters, '
|
|
||||||
'allowable (%s)' % (device, _ALLOWABLE_CH))
|
|
||||||
|
|
||||||
|
|
||||||
def validate_vg_name(interface, vg_name):
|
|
||||||
try:
|
|
||||||
_allowable_vg_name(vg_name)
|
|
||||||
except ValueError as ve:
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
interface, str(ve))
|
|
||||||
|
|
||||||
|
|
||||||
def validate_lv_name(interface, vg_name, lv_name):
|
|
||||||
try:
|
|
||||||
_allowable_lv_name(vg_name, lv_name)
|
|
||||||
except ValueError as ve:
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
interface, str(ve))
|
|
||||||
|
|
||||||
|
|
||||||
def validate_tag(interface, tag):
|
|
||||||
if not _allowable_tag(tag):
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
interface, 'tag (%s) contains invalid character, allowable set(%s)'
|
|
||||||
% (tag, _ALLOWABLE_TAG_CH))
|
|
||||||
@@ -1,959 +0,0 @@
|
|||||||
# 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/>.
|
|
||||||
|
|
||||||
from .automatedproperties import AutomatedProperties
|
|
||||||
|
|
||||||
from . import utils
|
|
||||||
from .utils import pv_obj_path_generate, vg_obj_path_generate, n
|
|
||||||
import dbus
|
|
||||||
from . import cfg
|
|
||||||
from .cfg import VG_INTERFACE
|
|
||||||
from . import cmdhandler
|
|
||||||
from .request import RequestEntry
|
|
||||||
from .loader import common
|
|
||||||
from .state import State
|
|
||||||
from . import background
|
|
||||||
from .utils import round_size
|
|
||||||
from .job import JobState
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyUnusedLocal
|
|
||||||
def vgs_state_retrieve(selection, cache_refresh=True):
|
|
||||||
rc = []
|
|
||||||
|
|
||||||
if cache_refresh:
|
|
||||||
cfg.db.refresh()
|
|
||||||
|
|
||||||
for v in cfg.db.fetch_vgs(selection):
|
|
||||||
rc.append(
|
|
||||||
VgState(
|
|
||||||
v['vg_uuid'], v['vg_name'], v['vg_fmt'], n(v['vg_size']),
|
|
||||||
n(v['vg_free']), v['vg_sysid'], n(v['vg_extent_size']),
|
|
||||||
n(v['vg_extent_count']), n(v['vg_free_count']),
|
|
||||||
v['vg_profile'], n(v['max_lv']), n(v['max_pv']),
|
|
||||||
n(v['pv_count']), n(v['lv_count']), n(v['snap_count']),
|
|
||||||
n(v['vg_seqno']), n(v['vg_mda_count']),
|
|
||||||
n(v['vg_mda_free']), n(v['vg_mda_size']),
|
|
||||||
n(v['vg_mda_used_count']), v['vg_attr'], v['vg_tags']))
|
|
||||||
return rc
|
|
||||||
|
|
||||||
|
|
||||||
def load_vgs(vg_specific=None, object_path=None, refresh=False,
|
|
||||||
emit_signal=False, cache_refresh=True):
|
|
||||||
return common(vgs_state_retrieve, (Vg,), vg_specific, object_path, refresh,
|
|
||||||
emit_signal, cache_refresh)
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyPep8Naming,PyUnresolvedReferences,PyUnusedLocal
|
|
||||||
class VgState(State):
|
|
||||||
@property
|
|
||||||
def lvm_id(self):
|
|
||||||
return self.Name
|
|
||||||
|
|
||||||
def identifiers(self):
|
|
||||||
return (self.Uuid, self.Name)
|
|
||||||
|
|
||||||
def _lv_paths_build(self):
|
|
||||||
rc = []
|
|
||||||
for lv in cfg.db.lvs_in_vg(self.Uuid):
|
|
||||||
(lv_name, meta, lv_uuid) = lv
|
|
||||||
full_name = "%s/%s" % (self.Name, lv_name)
|
|
||||||
|
|
||||||
gen = utils.lv_object_path_method(lv_name, meta)
|
|
||||||
|
|
||||||
lv_path = cfg.om.get_object_path_by_uuid_lvm_id(
|
|
||||||
lv_uuid, full_name, gen)
|
|
||||||
rc.append(lv_path)
|
|
||||||
return dbus.Array(rc, signature='o')
|
|
||||||
|
|
||||||
def _pv_paths_build(self):
|
|
||||||
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(
|
|
||||||
pv_uuid, pv_name, pv_obj_path_generate))
|
|
||||||
return dbus.Array(rc, signature='o')
|
|
||||||
|
|
||||||
def __init__(self, Uuid, Name, Fmt,
|
|
||||||
SizeBytes, FreeBytes, SysId, ExtentSizeBytes,
|
|
||||||
ExtentCount, FreeCount, Profile, MaxLv, MaxPv, PvCount,
|
|
||||||
LvCount, SnapCount, Seqno, MdaCount, MdaFree,
|
|
||||||
MdaSizeBytes, MdaUsedCount, attr, tags):
|
|
||||||
utils.init_class_from_arguments(self)
|
|
||||||
self.Pvs = self._pv_paths_build()
|
|
||||||
self.Lvs = self._lv_paths_build()
|
|
||||||
|
|
||||||
def create_dbus_object(self, path):
|
|
||||||
if not path:
|
|
||||||
path = cfg.om.get_object_path_by_uuid_lvm_id(
|
|
||||||
self.Uuid, self.Name, vg_obj_path_generate)
|
|
||||||
return Vg(path, self)
|
|
||||||
|
|
||||||
# noinspection PyMethodMayBeStatic
|
|
||||||
def creation_signature(self):
|
|
||||||
return (Vg, vg_obj_path_generate)
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyPep8Naming
|
|
||||||
@utils.dbus_property(VG_INTERFACE, 'Uuid', 's')
|
|
||||||
@utils.dbus_property(VG_INTERFACE, 'Name', 's')
|
|
||||||
@utils.dbus_property(VG_INTERFACE, 'Fmt', 's')
|
|
||||||
@utils.dbus_property(VG_INTERFACE, 'SizeBytes', 't', 0)
|
|
||||||
@utils.dbus_property(VG_INTERFACE, 'FreeBytes', 't', 0)
|
|
||||||
@utils.dbus_property(VG_INTERFACE, 'SysId', 's')
|
|
||||||
@utils.dbus_property(VG_INTERFACE, 'ExtentSizeBytes', 't')
|
|
||||||
@utils.dbus_property(VG_INTERFACE, 'ExtentCount', 't')
|
|
||||||
@utils.dbus_property(VG_INTERFACE, 'FreeCount', 't')
|
|
||||||
@utils.dbus_property(VG_INTERFACE, 'Profile', 's')
|
|
||||||
@utils.dbus_property(VG_INTERFACE, 'MaxLv', 't')
|
|
||||||
@utils.dbus_property(VG_INTERFACE, 'MaxPv', 't')
|
|
||||||
@utils.dbus_property(VG_INTERFACE, 'PvCount', 't')
|
|
||||||
@utils.dbus_property(VG_INTERFACE, 'LvCount', 't')
|
|
||||||
@utils.dbus_property(VG_INTERFACE, 'SnapCount', 't')
|
|
||||||
@utils.dbus_property(VG_INTERFACE, 'Seqno', 't')
|
|
||||||
@utils.dbus_property(VG_INTERFACE, 'MdaCount', 't')
|
|
||||||
@utils.dbus_property(VG_INTERFACE, 'MdaFree', 't')
|
|
||||||
@utils.dbus_property(VG_INTERFACE, 'MdaSizeBytes', 't')
|
|
||||||
@utils.dbus_property(VG_INTERFACE, 'MdaUsedCount', 't')
|
|
||||||
class Vg(AutomatedProperties):
|
|
||||||
_Tags_meta = ("as", VG_INTERFACE)
|
|
||||||
_Pvs_meta = ("ao", VG_INTERFACE)
|
|
||||||
_Lvs_meta = ("ao", VG_INTERFACE)
|
|
||||||
_Writeable_meta = ("b", VG_INTERFACE)
|
|
||||||
_Readable_meta = ("b", VG_INTERFACE)
|
|
||||||
_Resizeable_meta = ("b", VG_INTERFACE)
|
|
||||||
_Exportable_meta = ('b', VG_INTERFACE)
|
|
||||||
_Partial_meta = ('b', VG_INTERFACE)
|
|
||||||
_AllocContiguous_meta = ('b', VG_INTERFACE)
|
|
||||||
_AllocCling_meta = ('b', VG_INTERFACE)
|
|
||||||
_AllocNormal_meta = ('b', VG_INTERFACE)
|
|
||||||
_AllocAnywhere_meta = ('b', VG_INTERFACE)
|
|
||||||
_Clustered_meta = ('b', VG_INTERFACE)
|
|
||||||
|
|
||||||
# noinspection PyUnusedLocal,PyPep8Naming
|
|
||||||
def __init__(self, object_path, object_state):
|
|
||||||
super(Vg, self).__init__(object_path, vgs_state_retrieve)
|
|
||||||
self.set_interface(VG_INTERFACE)
|
|
||||||
self._object_path = object_path
|
|
||||||
self.state = object_state
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def fetch_new_lv(vg_name, lv_name):
|
|
||||||
cfg.load()
|
|
||||||
return cfg.om.get_object_by_lvm_id("%s/%s" % (vg_name, lv_name))
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _rename(uuid, vg_name, new_name, rename_options):
|
|
||||||
# Make sure we have a dbus object representing it
|
|
||||||
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(
|
|
||||||
dbus_interface=VG_INTERFACE,
|
|
||||||
in_signature='sia{sv}', out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def Rename(self, name, tmo, rename_options, cb, cbe):
|
|
||||||
utils.validate_vg_name(VG_INTERFACE, name)
|
|
||||||
r = RequestEntry(tmo, Vg._rename,
|
|
||||||
(self.state.Uuid, self.state.lvm_id, name,
|
|
||||||
rename_options), cb, cbe, False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _remove(uuid, vg_name, remove_options):
|
|
||||||
# Make sure we have a dbus object representing it
|
|
||||||
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(
|
|
||||||
dbus_interface=VG_INTERFACE,
|
|
||||||
in_signature='ia{sv}', out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def Remove(self, tmo, remove_options, cb, cbe):
|
|
||||||
r = RequestEntry(tmo, Vg._remove,
|
|
||||||
(self.state.Uuid, self.state.lvm_id, remove_options),
|
|
||||||
cb, cbe, False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _change(uuid, vg_name, change_options):
|
|
||||||
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:
|
|
||||||
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
|
|
||||||
# instead of having one method that takes a hash for parameters. Some of
|
|
||||||
# the changes that vgchange does works on entire system, not just a
|
|
||||||
# specfic vg, thus that should be in the Manager interface.
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=VG_INTERFACE,
|
|
||||||
in_signature='ia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def Change(self, tmo, change_options, cb, cbe):
|
|
||||||
r = RequestEntry(tmo, Vg._change,
|
|
||||||
(self.state.Uuid, self.state.lvm_id, change_options),
|
|
||||||
cb, cbe, False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _reduce(uuid, vg_name, missing, pv_object_paths, reduce_options):
|
|
||||||
# Make sure we have a dbus object representing it
|
|
||||||
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
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(
|
|
||||||
dbus_interface=VG_INTERFACE,
|
|
||||||
in_signature='baoia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def Reduce(self, missing, pv_object_paths, tmo, reduce_options, cb, cbe):
|
|
||||||
r = RequestEntry(tmo, Vg._reduce,
|
|
||||||
(self.state.Uuid, self.state.lvm_id, missing,
|
|
||||||
pv_object_paths, reduce_options), cb, cbe, False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _extend(uuid, vg_name, pv_object_paths, extend_options):
|
|
||||||
# Make sure we have a dbus object representing it
|
|
||||||
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
|
|
||||||
|
|
||||||
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)
|
|
||||||
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, 'No pv_object_paths provided!')
|
|
||||||
else:
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
VG_INTERFACE,
|
|
||||||
'VG with uuid %s and name %s not present!' %
|
|
||||||
(uuid, vg_name))
|
|
||||||
return '/'
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=VG_INTERFACE,
|
|
||||||
in_signature='aoia{sv}', out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def Extend(self, pv_object_paths, tmo, extend_options, cb, cbe):
|
|
||||||
r = RequestEntry(tmo, Vg._extend,
|
|
||||||
(self.state.Uuid, self.state.lvm_id, pv_object_paths,
|
|
||||||
extend_options),
|
|
||||||
cb, cbe, False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=VG_INTERFACE,
|
|
||||||
in_signature='o(tt)a(ott)ia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
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)
|
|
||||||
|
|
||||||
@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)
|
|
||||||
|
|
||||||
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])
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
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,
|
|
||||||
in_signature='sta(ott)ia{sv}',
|
|
||||||
out_signature='(oo)',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def LvCreate(self, name, size_bytes, pv_dests_and_ranges,
|
|
||||||
tmo, create_options, cb, cbe):
|
|
||||||
"""
|
|
||||||
This one it for the advanced users that want to roll their own
|
|
||||||
:param name: Name of the LV
|
|
||||||
:param size_bytes: Size of LV in bytes
|
|
||||||
:param pv_dests_and_ranges: Optional array of PV object paths and
|
|
||||||
ranges
|
|
||||||
:param tmo: -1 == Wait forever, 0 == return job immediately, > 0 ==
|
|
||||||
willing to wait that number of seconds before
|
|
||||||
getting a job
|
|
||||||
:param create_options: hash of key/value pairs
|
|
||||||
:param cb: Internal, not accessible by dbus API user
|
|
||||||
:param cbe: Internal, not accessible by dbus API user
|
|
||||||
:return: (oo) First object path is newly created object, second is
|
|
||||||
job object path if created. Each == '/' when it doesn't
|
|
||||||
apply.
|
|
||||||
"""
|
|
||||||
utils.validate_lv_name(VG_INTERFACE, self.Name, name)
|
|
||||||
r = RequestEntry(tmo, Vg._lv_create,
|
|
||||||
(self.state.Uuid, self.state.lvm_id,
|
|
||||||
name, round_size(size_bytes), pv_dests_and_ranges,
|
|
||||||
create_options), cb, cbe)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _lv_create_linear(uuid, vg_name, name, size_bytes,
|
|
||||||
thin_pool, create_options):
|
|
||||||
# Make sure we have a dbus object representing it
|
|
||||||
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
|
|
||||||
|
|
||||||
if dbo:
|
|
||||||
rc, out, err = cmdhandler.vg_lv_create_linear(
|
|
||||||
vg_name, create_options, name, size_bytes, 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,
|
|
||||||
in_signature='stbia{sv}',
|
|
||||||
out_signature='(oo)',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def LvCreateLinear(self, name, size_bytes,
|
|
||||||
thin_pool, tmo, create_options, cb, cbe):
|
|
||||||
utils.validate_lv_name(VG_INTERFACE, self.Name, name)
|
|
||||||
r = RequestEntry(tmo, Vg._lv_create_linear,
|
|
||||||
(self.state.Uuid, self.state.lvm_id,
|
|
||||||
name, round_size(size_bytes), thin_pool,
|
|
||||||
create_options), cb, cbe)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
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
|
|
||||||
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,
|
|
||||||
in_signature='stuubia{sv}',
|
|
||||||
out_signature='(oo)',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def LvCreateStriped(self, name, size_bytes, num_stripes,
|
|
||||||
stripe_size_kb, thin_pool, tmo, create_options,
|
|
||||||
cb, cbe):
|
|
||||||
utils.validate_lv_name(VG_INTERFACE, self.Name, name)
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, Vg._lv_create_striped,
|
|
||||||
(self.state.Uuid, self.state.lvm_id, name,
|
|
||||||
round_size(size_bytes), num_stripes, stripe_size_kb,
|
|
||||||
thin_pool, create_options),
|
|
||||||
cb, cbe)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _lv_create_mirror(uuid, vg_name, name, size_bytes,
|
|
||||||
num_copies, create_options):
|
|
||||||
# Make sure we have a dbus object representing it
|
|
||||||
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,
|
|
||||||
in_signature='stuia{sv}',
|
|
||||||
out_signature='(oo)',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def LvCreateMirror(self, name, size_bytes, num_copies,
|
|
||||||
tmo, create_options, cb, cbe):
|
|
||||||
utils.validate_lv_name(VG_INTERFACE, self.Name, name)
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, Vg._lv_create_mirror,
|
|
||||||
(self.state.Uuid, self.state.lvm_id, name,
|
|
||||||
round_size(size_bytes), num_copies,
|
|
||||||
create_options), cb, cbe)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
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
|
|
||||||
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,
|
|
||||||
in_signature='sstuuia{sv}',
|
|
||||||
out_signature='(oo)',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def LvCreateRaid(self, name, raid_type, size_bytes,
|
|
||||||
num_stripes, stripe_size_kb, tmo,
|
|
||||||
create_options, cb, cbe):
|
|
||||||
utils.validate_lv_name(VG_INTERFACE, self.Name, name)
|
|
||||||
r = RequestEntry(tmo, Vg._lv_create_raid,
|
|
||||||
(self.state.Uuid, self.state.lvm_id, name,
|
|
||||||
raid_type, round_size(size_bytes), num_stripes,
|
|
||||||
stripe_size_kb, create_options), cb, cbe)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _create_pool(uuid, vg_name, meta_data_lv, data_lv,
|
|
||||||
create_options, create_method):
|
|
||||||
# Make sure we have a dbus object representing it
|
|
||||||
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 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:
|
|
||||||
cfg.om.remove_object(md, emit_signal=True)
|
|
||||||
cfg.om.remove_object(data, emit_signal=True)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
if not data_lv:
|
|
||||||
msg += 'Data LV with object path %s not present!' % \
|
|
||||||
(meta_data_lv)
|
|
||||||
|
|
||||||
raise dbus.exceptions.DBusException(VG_INTERFACE, msg)
|
|
||||||
|
|
||||||
return cache_pool_lv
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=VG_INTERFACE,
|
|
||||||
in_signature='ooia{sv}',
|
|
||||||
out_signature='(oo)',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def CreateCachePool(self, meta_data_lv, data_lv, tmo, create_options,
|
|
||||||
cb, cbe):
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, Vg._create_pool,
|
|
||||||
(self.state.Uuid, self.state.lvm_id, meta_data_lv,
|
|
||||||
data_lv, create_options, cmdhandler.vg_create_cache_pool), cb, cbe)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=VG_INTERFACE,
|
|
||||||
in_signature='ooia{sv}',
|
|
||||||
out_signature='(oo)',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def CreateThinPool(self, meta_data_lv, data_lv, tmo, create_options,
|
|
||||||
cb, cbe):
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, Vg._create_pool,
|
|
||||||
(self.state.Uuid, self.state.lvm_id, meta_data_lv,
|
|
||||||
data_lv, create_options, cmdhandler.vg_create_thin_pool), cb, cbe)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _pv_add_rm_tags(uuid, vg_name, pv_object_paths, tags_add,
|
|
||||||
tags_del, tag_options):
|
|
||||||
pv_devices = []
|
|
||||||
|
|
||||||
# Make sure we have a dbus object representing it
|
|
||||||
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_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,
|
|
||||||
'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,
|
|
||||||
in_signature='aoasia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def PvTagsAdd(self, pvs, tags, tmo, tag_options, cb, cbe):
|
|
||||||
|
|
||||||
for t in tags:
|
|
||||||
utils.validate_tag(VG_INTERFACE, t)
|
|
||||||
|
|
||||||
r = RequestEntry(tmo, Vg._pv_add_rm_tags,
|
|
||||||
(self.state.Uuid, self.state.lvm_id,
|
|
||||||
pvs, tags, None, tag_options),
|
|
||||||
cb, cbe, return_tuple=False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=VG_INTERFACE,
|
|
||||||
in_signature='aoasia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def PvTagsDel(self, pvs, tags, tmo, tag_options, cb, cbe):
|
|
||||||
|
|
||||||
for t in tags:
|
|
||||||
utils.validate_tag(VG_INTERFACE, t)
|
|
||||||
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, Vg._pv_add_rm_tags,
|
|
||||||
(self.state.Uuid, self.state.lvm_id,
|
|
||||||
pvs, None, tags, tag_options),
|
|
||||||
cb, cbe, return_tuple=False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _vg_add_rm_tags(uuid, vg_name, tags_add, tags_del, tag_options):
|
|
||||||
# Make sure we have a dbus object representing it
|
|
||||||
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
|
|
||||||
|
|
||||||
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,
|
|
||||||
in_signature='asia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def TagsAdd(self, tags, tmo, tag_options, cb, cbe):
|
|
||||||
|
|
||||||
for t in tags:
|
|
||||||
utils.validate_tag(VG_INTERFACE, t)
|
|
||||||
|
|
||||||
r = RequestEntry(tmo, Vg._vg_add_rm_tags,
|
|
||||||
(self.state.Uuid, self.state.lvm_id,
|
|
||||||
tags, None, tag_options),
|
|
||||||
cb, cbe, return_tuple=False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=VG_INTERFACE,
|
|
||||||
in_signature='asia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def TagsDel(self, tags, tmo, tag_options, cb, cbe):
|
|
||||||
|
|
||||||
for t in tags:
|
|
||||||
utils.validate_tag(VG_INTERFACE, t)
|
|
||||||
|
|
||||||
r = RequestEntry(tmo, Vg._vg_add_rm_tags,
|
|
||||||
(self.state.Uuid, self.state.lvm_id,
|
|
||||||
None, tags, tag_options),
|
|
||||||
cb, cbe, return_tuple=False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _vg_change_set(uuid, vg_name, method, value, options):
|
|
||||||
# Make sure we have a dbus object representing it
|
|
||||||
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,
|
|
||||||
in_signature='sia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def AllocationPolicySet(self, policy, tmo, policy_options, cb, cbe):
|
|
||||||
r = RequestEntry(tmo, Vg._vg_change_set,
|
|
||||||
(self.state.Uuid, self.state.lvm_id,
|
|
||||||
cmdhandler.vg_allocation_policy,
|
|
||||||
policy, policy_options),
|
|
||||||
cb, cbe, return_tuple=False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=VG_INTERFACE,
|
|
||||||
in_signature='tia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def MaxPvSet(self, number, tmo, max_options, cb, cbe):
|
|
||||||
r = RequestEntry(tmo, Vg._vg_change_set,
|
|
||||||
(self.state.Uuid, self.state.lvm_id,
|
|
||||||
cmdhandler.vg_max_pv, number, max_options),
|
|
||||||
cb, cbe, return_tuple=False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=VG_INTERFACE,
|
|
||||||
in_signature='ia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def UuidGenerate(self, tmo, options, cb, cbe):
|
|
||||||
r = RequestEntry(tmo, Vg._vg_change_set,
|
|
||||||
(self.state.Uuid, self.state.lvm_id,
|
|
||||||
cmdhandler.vg_uuid_gen, None, options),
|
|
||||||
cb, cbe, return_tuple=False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
def _attribute(self, pos, ch):
|
|
||||||
if self.state.attr[pos] == ch:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=VG_INTERFACE,
|
|
||||||
in_signature='tia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def MaxLvSet(self, number, tmo, max_options, cb, cbe):
|
|
||||||
r = RequestEntry(tmo, Vg._vg_change_set,
|
|
||||||
(self.state.Uuid, self.state.lvm_id,
|
|
||||||
cmdhandler.vg_max_lv, number, max_options),
|
|
||||||
cb, cbe, return_tuple=False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _vg_activate_deactivate(uuid, vg_name, activate, control_flags,
|
|
||||||
options):
|
|
||||||
# Make sure we have a dbus object representing it
|
|
||||||
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,
|
|
||||||
in_signature='tia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def Activate(self, control_flags, tmo, activate_options, cb, cbe):
|
|
||||||
r = RequestEntry(tmo, Vg._vg_activate_deactivate,
|
|
||||||
(self.state.Uuid, self.state.lvm_id, True,
|
|
||||||
control_flags, activate_options),
|
|
||||||
cb, cbe, return_tuple=False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=VG_INTERFACE,
|
|
||||||
in_signature='tia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def Deactivate(self, control_flags, tmo, activate_options, cb, cbe):
|
|
||||||
r = RequestEntry(tmo, Vg._vg_activate_deactivate,
|
|
||||||
(self.state.Uuid, self.state.lvm_id, False,
|
|
||||||
control_flags, activate_options),
|
|
||||||
cb, cbe, return_tuple=False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def Tags(self):
|
|
||||||
return utils.parse_tags(self.state.tags)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def Pvs(self):
|
|
||||||
return self.state.Pvs
|
|
||||||
|
|
||||||
@property
|
|
||||||
def Lvs(self):
|
|
||||||
return self.state.Lvs
|
|
||||||
|
|
||||||
@property
|
|
||||||
def lvm_id(self):
|
|
||||||
return self.state.lvm_id
|
|
||||||
|
|
||||||
@property
|
|
||||||
def Writeable(self):
|
|
||||||
return self._attribute(0, 'w')
|
|
||||||
|
|
||||||
@property
|
|
||||||
def Readable(self):
|
|
||||||
return self._attribute(0, 'r')
|
|
||||||
|
|
||||||
@property
|
|
||||||
def Resizeable(self):
|
|
||||||
return self._attribute(1, 'z')
|
|
||||||
|
|
||||||
@property
|
|
||||||
def Exportable(self):
|
|
||||||
return self._attribute(2, 'x')
|
|
||||||
|
|
||||||
@property
|
|
||||||
def Partial(self):
|
|
||||||
return self._attribute(3, 'p')
|
|
||||||
|
|
||||||
@property
|
|
||||||
def AllocContiguous(self):
|
|
||||||
return self._attribute(4, 'c')
|
|
||||||
|
|
||||||
@property
|
|
||||||
def AllocCling(self):
|
|
||||||
return self._attribute(4, 'l')
|
|
||||||
|
|
||||||
@property
|
|
||||||
def AllocNormal(self):
|
|
||||||
return self._attribute(4, 'n')
|
|
||||||
|
|
||||||
@property
|
|
||||||
def AllocAnywhere(self):
|
|
||||||
return self._attribute(4, 'a')
|
|
||||||
|
|
||||||
@property
|
|
||||||
def Clustered(self):
|
|
||||||
return self._attribute(5, 'c')
|
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# 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,
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
srcdir = @srcdir@
|
srcdir = @srcdir@
|
||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
@@ -45,8 +45,6 @@ lvmetactl: lvmetactl.o $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
|||||||
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmetactl.o $(LVMLIBS)
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmetactl.o $(LVMLIBS)
|
||||||
|
|
||||||
CLEAN_TARGETS += lvmetactl.o
|
|
||||||
|
|
||||||
# TODO: No idea. No idea how to test either.
|
# TODO: No idea. No idea how to test either.
|
||||||
#ifneq ("$(CFLOW_CMD)", "")
|
#ifneq ("$(CFLOW_CMD)", "")
|
||||||
#CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
#CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
||||||
|
|||||||
@@ -34,17 +34,16 @@ int main(int argc, char **argv)
|
|||||||
int ver;
|
int ver;
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
printf("lvmetactl dump\n");
|
printf("lvmeta dump\n");
|
||||||
printf("lvmetactl pv_list\n");
|
printf("lvmeta pv_list\n");
|
||||||
printf("lvmetactl vg_list\n");
|
printf("lvmeta vg_list\n");
|
||||||
printf("lvmetactl get_global_info\n");
|
printf("lvmeta vg_lookup_name <name>\n");
|
||||||
printf("lvmetactl vg_lookup_name <name>\n");
|
printf("lvmeta vg_lookup_uuid <uuid>\n");
|
||||||
printf("lvmetactl vg_lookup_uuid <uuid>\n");
|
printf("lvmeta pv_lookup_uuid <uuid>\n");
|
||||||
printf("lvmetactl pv_lookup_uuid <uuid>\n");
|
printf("lvmeta set_global_invalid 0|1\n");
|
||||||
printf("lvmetactl set_global_invalid 0|1\n");
|
printf("lvmeta get_global_invalid\n");
|
||||||
printf("lvmetactl set_global_disable 0|1\n");
|
printf("lvmeta set_vg_version <uuid> <version>\n");
|
||||||
printf("lvmetactl set_vg_version <uuid> <name> <version>\n");
|
printf("lvmeta vg_lock_type <uuid>\n");
|
||||||
printf("lvmetactl vg_lock_type <uuid>\n");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,32 +54,18 @@ int main(int argc, char **argv)
|
|||||||
if (!strcmp(cmd, "dump")) {
|
if (!strcmp(cmd, "dump")) {
|
||||||
reply = daemon_send_simple(h, "dump",
|
reply = daemon_send_simple(h, "dump",
|
||||||
"token = %s", "skip",
|
"token = %s", "skip",
|
||||||
"pid = " FMTd64, (int64_t)getpid(),
|
|
||||||
"cmd = %s", "lvmetactl",
|
|
||||||
NULL);
|
NULL);
|
||||||
printf("%s\n", reply.buffer.mem);
|
printf("%s\n", reply.buffer.mem);
|
||||||
|
|
||||||
} else if (!strcmp(cmd, "pv_list")) {
|
} else if (!strcmp(cmd, "pv_list")) {
|
||||||
reply = daemon_send_simple(h, "pv_list",
|
reply = daemon_send_simple(h, "pv_list",
|
||||||
"token = %s", "skip",
|
"token = %s", "skip",
|
||||||
"pid = " FMTd64, (int64_t)getpid(),
|
|
||||||
"cmd = %s", "lvmetactl",
|
|
||||||
NULL);
|
NULL);
|
||||||
printf("%s\n", reply.buffer.mem);
|
printf("%s\n", reply.buffer.mem);
|
||||||
|
|
||||||
} else if (!strcmp(cmd, "vg_list")) {
|
} else if (!strcmp(cmd, "vg_list")) {
|
||||||
reply = daemon_send_simple(h, "vg_list",
|
reply = daemon_send_simple(h, "vg_list",
|
||||||
"token = %s", "skip",
|
"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);
|
NULL);
|
||||||
printf("%s\n", reply.buffer.mem);
|
printf("%s\n", reply.buffer.mem);
|
||||||
|
|
||||||
@@ -92,73 +77,30 @@ int main(int argc, char **argv)
|
|||||||
val = atoi(argv[2]);
|
val = atoi(argv[2]);
|
||||||
|
|
||||||
reply = daemon_send_simple(h, "set_global_info",
|
reply = daemon_send_simple(h, "set_global_info",
|
||||||
"global_invalid = " FMTd64, (int64_t) val,
|
"global_invalid = %d", val,
|
||||||
"token = %s", "skip",
|
"token = %s", "skip",
|
||||||
"pid = " FMTd64, (int64_t)getpid(),
|
|
||||||
"cmd = %s", "lvmetactl",
|
|
||||||
NULL);
|
NULL);
|
||||||
print_reply(reply);
|
print_reply(reply);
|
||||||
|
|
||||||
} else if (!strcmp(cmd, "set_global_disable")) {
|
} else if (!strcmp(cmd, "get_global_invalid")) {
|
||||||
if (argc < 3) {
|
reply = daemon_send_simple(h, "get_global_info",
|
||||||
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,
|
|
||||||
"token = %s", "skip",
|
"token = %s", "skip",
|
||||||
"pid = " FMTd64, (int64_t)getpid(),
|
|
||||||
"cmd = %s", "lvmetactl",
|
|
||||||
NULL);
|
NULL);
|
||||||
print_reply(reply);
|
printf("%s\n", reply.buffer.mem);
|
||||||
|
|
||||||
} else if (!strcmp(cmd, "set_vg_version")) {
|
} else if (!strcmp(cmd, "set_vg_version")) {
|
||||||
if (argc < 5) {
|
if (argc < 4) {
|
||||||
printf("set_vg_version <uuid> <name> <ver>\n");
|
printf("set_vg_version <uuid> <ver>\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
uuid = argv[2];
|
uuid = argv[2];
|
||||||
name = argv[3];
|
ver = atoi(argv[3]);
|
||||||
ver = atoi(argv[4]);
|
|
||||||
|
|
||||||
if ((strlen(uuid) == 1) && (uuid[0] == '-'))
|
|
||||||
uuid = NULL;
|
|
||||||
if ((strlen(name) == 1) && (name[0] == '-'))
|
|
||||||
name = NULL;
|
|
||||||
|
|
||||||
if (uuid && name) {
|
|
||||||
reply = daemon_send_simple(h, "set_vg_info",
|
|
||||||
"uuid = %s", uuid,
|
|
||||||
"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");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
reply = daemon_send_simple(h, "set_vg_info",
|
||||||
|
"uuid = %s", uuid,
|
||||||
|
"version = %d", ver,
|
||||||
|
"token = %s", "skip",
|
||||||
|
NULL);
|
||||||
print_reply(reply);
|
print_reply(reply);
|
||||||
|
|
||||||
} else if (!strcmp(cmd, "vg_lookup_name")) {
|
} else if (!strcmp(cmd, "vg_lookup_name")) {
|
||||||
@@ -171,8 +113,6 @@ int main(int argc, char **argv)
|
|||||||
reply = daemon_send_simple(h, "vg_lookup",
|
reply = daemon_send_simple(h, "vg_lookup",
|
||||||
"name = %s", name,
|
"name = %s", name,
|
||||||
"token = %s", "skip",
|
"token = %s", "skip",
|
||||||
"pid = " FMTd64, (int64_t)getpid(),
|
|
||||||
"cmd = %s", "lvmetactl",
|
|
||||||
NULL);
|
NULL);
|
||||||
printf("%s\n", reply.buffer.mem);
|
printf("%s\n", reply.buffer.mem);
|
||||||
|
|
||||||
@@ -186,8 +126,6 @@ int main(int argc, char **argv)
|
|||||||
reply = daemon_send_simple(h, "vg_lookup",
|
reply = daemon_send_simple(h, "vg_lookup",
|
||||||
"uuid = %s", uuid,
|
"uuid = %s", uuid,
|
||||||
"token = %s", "skip",
|
"token = %s", "skip",
|
||||||
"pid = " FMTd64, (int64_t)getpid(),
|
|
||||||
"cmd = %s", "lvmetactl",
|
|
||||||
NULL);
|
NULL);
|
||||||
printf("%s\n", reply.buffer.mem);
|
printf("%s\n", reply.buffer.mem);
|
||||||
|
|
||||||
@@ -204,8 +142,6 @@ int main(int argc, char **argv)
|
|||||||
reply = daemon_send_simple(h, "vg_lookup",
|
reply = daemon_send_simple(h, "vg_lookup",
|
||||||
"uuid = %s", uuid,
|
"uuid = %s", uuid,
|
||||||
"token = %s", "skip",
|
"token = %s", "skip",
|
||||||
"pid = " FMTd64, (int64_t)getpid(),
|
|
||||||
"cmd = %s", "lvmetactl",
|
|
||||||
NULL);
|
NULL);
|
||||||
/* printf("%s\n", reply.buffer.mem); */
|
/* printf("%s\n", reply.buffer.mem); */
|
||||||
|
|
||||||
@@ -232,8 +168,6 @@ int main(int argc, char **argv)
|
|||||||
reply = daemon_send_simple(h, "pv_lookup",
|
reply = daemon_send_simple(h, "pv_lookup",
|
||||||
"uuid = %s", uuid,
|
"uuid = %s", uuid,
|
||||||
"token = %s", "skip",
|
"token = %s", "skip",
|
||||||
"pid = " FMTd64, (int64_t)getpid(),
|
|
||||||
"cmd = %s", "lvmetactl",
|
|
||||||
NULL);
|
NULL);
|
||||||
printf("%s\n", reply.buffer.mem);
|
printf("%s\n", reply.buffer.mem);
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* 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,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LVM_LVMETAD_CLIENT_H
|
#ifndef _LVM_LVMETAD_CLIENT_H
|
||||||
@@ -19,13 +19,6 @@
|
|||||||
|
|
||||||
#define LVMETAD_SOCKET DEFAULT_RUN_DIR "/lvmetad.socket"
|
#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;
|
struct volume_group;
|
||||||
|
|
||||||
/* Different types of replies we may get from lvmetad. */
|
/* Different types of replies we may get from lvmetad. */
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
#include "tool.h"
|
#include "tool.h"
|
||||||
|
|
||||||
@@ -75,10 +75,7 @@ int scan(daemon_handle h, char *fn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char uuid[64];
|
char uuid[64];
|
||||||
if (!id_write_format(dev->pvid, uuid, 64)) {
|
id_write_format(dev->pvid, uuid, 64);
|
||||||
fprintf(stderr, "[C] Failed to format PV UUID for %s", dev_name(dev));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fprintf(stderr, "[C] found PV: %s\n", uuid);
|
fprintf(stderr, "[C] found PV: %s\n", uuid);
|
||||||
struct lvmcache_info *info = (struct lvmcache_info *) label->info;
|
struct lvmcache_info *info = (struct lvmcache_info *) label->info;
|
||||||
struct physical_volume pv = { 0, };
|
struct physical_volume pv = { 0, };
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# 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,
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
srcdir = @srcdir@
|
srcdir = @srcdir@
|
||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
|
||||||
@@ -77,7 +78,7 @@ static void save_client_info(char *line)
|
|||||||
uint32_t client_id = 0;
|
uint32_t client_id = 0;
|
||||||
char name[MAX_NAME+1] = { 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);
|
&pid, &fd, &pi, &client_id, name);
|
||||||
|
|
||||||
clients[num_clients].client_id = client_id;
|
clients[num_clients].client_id = client_id;
|
||||||
@@ -110,7 +111,7 @@ static void format_info_ls(char *line)
|
|||||||
char lock_args[MAX_ARGS+1] = { 0 };
|
char lock_args[MAX_ARGS+1] = { 0 };
|
||||||
char lock_type[MAX_NAME+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);
|
ls_name, vg_name, vg_uuid, vg_sysid, lock_args, lock_type);
|
||||||
|
|
||||||
if (!first_ls)
|
if (!first_ls)
|
||||||
@@ -131,7 +132,7 @@ static void format_info_ls_action(char *line)
|
|||||||
uint32_t pid = 0;
|
uint32_t pid = 0;
|
||||||
char cl_name[MAX_NAME+1] = { 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);
|
&client_id, flags, version, op);
|
||||||
|
|
||||||
find_client_info(client_id, &pid, cl_name);
|
find_client_info(client_id, &pid, cl_name);
|
||||||
@@ -147,15 +148,16 @@ static void format_info_r(char *line, char *r_name_out, char *r_type_out)
|
|||||||
char sh_count[MAX_NAME+1] = { 0 };
|
char sh_count[MAX_NAME+1] = { 0 };
|
||||||
uint32_t ver = 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);
|
r_name, r_type, mode, sh_count, &ver);
|
||||||
|
|
||||||
strcpy(r_name_out, r_name);
|
|
||||||
strcpy(r_type_out, r_type);
|
|
||||||
|
|
||||||
/* when mode is not un, wait and print each lk line */
|
/* when mode is not un, wait and print each lk line */
|
||||||
if (strcmp(mode, "un"))
|
|
||||||
|
if (strcmp(mode, "un")) {
|
||||||
|
strcpy(r_name_out, r_name);
|
||||||
|
strcpy(r_type_out, r_type);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* when mode is un, there will be no lk lines, so print now */
|
/* when mode is un, there will be no lk lines, so print now */
|
||||||
|
|
||||||
@@ -185,7 +187,7 @@ static void format_info_lk(char *line, char *r_name, char *r_type)
|
|||||||
return;
|
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);
|
mode, &ver, flags, &client_id);
|
||||||
|
|
||||||
find_client_info(client_id, &pid, cl_name);
|
find_client_info(client_id, &pid, cl_name);
|
||||||
@@ -221,13 +223,13 @@ static void format_info_r_action(char *line, char *r_name, char *r_type)
|
|||||||
return;
|
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);
|
&client_id, flags, version, op, rt, mode, lm, result, lm_rv);
|
||||||
|
|
||||||
find_client_info(client_id, &pid, cl_name);
|
find_client_info(client_id, &pid, cl_name);
|
||||||
|
|
||||||
if (strcmp(op, "lock")) {
|
if (strcmp(op, "lock")) {
|
||||||
printf("OP %s pid %u (%s)\n", op, pid, cl_name);
|
printf("OP %s pid %u (%s)", op, pid, cl_name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -378,7 +380,6 @@ static int setup_dump_socket(void)
|
|||||||
|
|
||||||
rv = bind(s, (struct sockaddr *) &dump_addr, dump_addrlen);
|
rv = bind(s, (struct sockaddr *) &dump_addr, dump_addrlen);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
rv = -errno;
|
|
||||||
if (!close(s))
|
if (!close(s))
|
||||||
log_error("failed to close dump socket");
|
log_error("failed to close dump socket");
|
||||||
return rv;
|
return rv;
|
||||||
@@ -392,7 +393,6 @@ static int do_dump(const char *req_name)
|
|||||||
daemon_reply reply;
|
daemon_reply reply;
|
||||||
int result;
|
int result;
|
||||||
int fd, rv = 0;
|
int fd, rv = 0;
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
fd = setup_dump_socket();
|
fd = setup_dump_socket();
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
@@ -423,18 +423,13 @@ static int do_dump(const char *req_name)
|
|||||||
|
|
||||||
memset(dump_buf, 0, sizeof(dump_buf));
|
memset(dump_buf, 0, sizeof(dump_buf));
|
||||||
|
|
||||||
retry:
|
rv = recvfrom(fd, dump_buf, dump_len, MSG_WAITALL,
|
||||||
rv = recvfrom(fd, dump_buf + count, dump_len - count, MSG_WAITALL,
|
|
||||||
(struct sockaddr *)&dump_addr, &dump_addrlen);
|
(struct sockaddr *)&dump_addr, &dump_addrlen);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
log_error("recvfrom error %d %d", rv, errno);
|
log_error("recvfrom error %d %d", rv, errno);
|
||||||
rv = -errno;
|
rv = -errno;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
count += rv;
|
|
||||||
|
|
||||||
if (count < dump_len)
|
|
||||||
goto retry;
|
|
||||||
|
|
||||||
rv = 0;
|
rv = 0;
|
||||||
if ((info && dump) || !strcmp(req_name, "dump"))
|
if ((info && dump) || !strcmp(req_name, "dump"))
|
||||||
@@ -455,7 +450,7 @@ static int do_able(const char *req_name)
|
|||||||
|
|
||||||
reply = _lvmlockd_send(req_name,
|
reply = _lvmlockd_send(req_name,
|
||||||
"cmd = %s", "lvmlockctl",
|
"cmd = %s", "lvmlockctl",
|
||||||
"pid = " FMTd64, (int64_t) getpid(),
|
"pid = %d", getpid(),
|
||||||
"vg_name = %s", arg_vg_name,
|
"vg_name = %s", arg_vg_name,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
@@ -486,7 +481,7 @@ static int do_stop_lockspaces(void)
|
|||||||
|
|
||||||
reply = _lvmlockd_send("stop_all",
|
reply = _lvmlockd_send("stop_all",
|
||||||
"cmd = %s", "lvmlockctl",
|
"cmd = %s", "lvmlockctl",
|
||||||
"pid = " FMTd64, (int64_t) getpid(),
|
"pid = %d", getpid(),
|
||||||
"opts = %s", opts[0] ? opts : "none",
|
"opts = %s", opts[0] ? opts : "none",
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
@@ -521,7 +516,7 @@ static int do_kill(void)
|
|||||||
|
|
||||||
reply = _lvmlockd_send("kill_vg",
|
reply = _lvmlockd_send("kill_vg",
|
||||||
"cmd = %s", "lvmlockctl",
|
"cmd = %s", "lvmlockctl",
|
||||||
"pid = " FMTd64, (int64_t) getpid(),
|
"pid = %d", getpid(),
|
||||||
"vg_name = %s", arg_vg_name,
|
"vg_name = %s", arg_vg_name,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
@@ -567,7 +562,7 @@ static int do_drop(void)
|
|||||||
|
|
||||||
reply = _lvmlockd_send("drop_vg",
|
reply = _lvmlockd_send("drop_vg",
|
||||||
"cmd = %s", "lvmlockctl",
|
"cmd = %s", "lvmlockctl",
|
||||||
"pid = " FMTd64, (int64_t) getpid(),
|
"pid = %d", getpid(),
|
||||||
"vg_name = %s", arg_vg_name,
|
"vg_name = %s", arg_vg_name,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
@@ -598,14 +593,14 @@ static void print_usage(void)
|
|||||||
printf(" Wait option for other commands.\n");
|
printf(" Wait option for other commands.\n");
|
||||||
printf("--force | -f 0|1>\n");
|
printf("--force | -f 0|1>\n");
|
||||||
printf(" Force option for other commands.\n");
|
printf(" Force option for other commands.\n");
|
||||||
printf("--kill | -k <vgname>\n");
|
printf("--kill | -k <vg_name>\n");
|
||||||
printf(" Kill access to the VG when sanlock cannot renew lease.\n");
|
printf(" Kill access to the vg when sanlock cannot renew lease.\n");
|
||||||
printf("--drop | -r <vgname>\n");
|
printf("--drop | -r <vg_name>\n");
|
||||||
printf(" Clear locks for the VG when it is unused after kill (-k).\n");
|
printf(" Clear locks for the vg after it has been killed and is no longer used.\n");
|
||||||
printf("--gl-enable | -E <vgname>\n");
|
printf("--gl-enable <vg_name>\n");
|
||||||
printf(" Tell lvmlockd to enable the global lock in a sanlock VG.\n");
|
printf(" Tell lvmlockd to enable the global lock in a sanlock vg.\n");
|
||||||
printf("--gl-disable | -D <vgname>\n");
|
printf("--gl-disable <vg_name>\n");
|
||||||
printf(" Tell lvmlockd to disable the global lock in a sanlock VG.\n");
|
printf(" Tell lvmlockd to disable the global lock in a sanlock vg.\n");
|
||||||
printf("--stop-lockspaces | -S\n");
|
printf("--stop-lockspaces | -S\n");
|
||||||
printf(" Stop all lockspaces.\n");
|
printf(" Stop all lockspaces.\n");
|
||||||
}
|
}
|
||||||
@@ -730,13 +725,11 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (gl_enable) {
|
if (gl_enable) {
|
||||||
syslog(LOG_INFO, "Enabling global lock in VG %s.", arg_vg_name);
|
|
||||||
rv = do_able("enable_gl");
|
rv = do_able("enable_gl");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gl_disable) {
|
if (gl_disable) {
|
||||||
syslog(LOG_INFO, "Disabling global lock in VG %s.", arg_vg_name);
|
|
||||||
rv = do_able("disable_gl");
|
rv = do_able("disable_gl");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,5 @@ static inline void lvmlockd_close(daemon_handle h)
|
|||||||
#define ELOCKD 216
|
#define ELOCKD 216
|
||||||
#define EVGKILLED 217 /* sanlock lost access to leases and VG is killed. */
|
#define EVGKILLED 217 /* sanlock lost access to leases and VG is killed. */
|
||||||
#define ELOCKIO 218 /* sanlock io errors during lock op, may be transient. */
|
#define ELOCKIO 218 /* sanlock io errors during lock op, may be transient. */
|
||||||
#define EREMOVED 219
|
|
||||||
|
|
||||||
#endif /* _LVM_LVMLOCKD_CLIENT_H */
|
#endif /* _LVM_LVMLOCKD_CLIENT_H */
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -14,6 +14,7 @@
|
|||||||
#include "tool.h"
|
#include "tool.h"
|
||||||
|
|
||||||
#include "daemon-server.h"
|
#include "daemon-server.h"
|
||||||
|
#include "daemon-log.h"
|
||||||
#include "xlate.h"
|
#include "xlate.h"
|
||||||
|
|
||||||
#include "lvmlockd-internal.h"
|
#include "lvmlockd-internal.h"
|
||||||
@@ -25,6 +26,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "libdlm.h"
|
#include "libdlm.h"
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -33,6 +35,7 @@
|
|||||||
#include <byteswap.h>
|
#include <byteswap.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
struct lm_dlm {
|
struct lm_dlm {
|
||||||
dlm_lshandle_t *dh;
|
dlm_lshandle_t *dh;
|
||||||
@@ -64,8 +67,6 @@ int lm_data_size_dlm(void)
|
|||||||
#define VG_LOCK_ARGS_MINOR 0
|
#define VG_LOCK_ARGS_MINOR 0
|
||||||
#define VG_LOCK_ARGS_PATCH 0
|
#define VG_LOCK_ARGS_PATCH 0
|
||||||
|
|
||||||
static int dlm_has_lvb_bug;
|
|
||||||
|
|
||||||
static int cluster_name_from_args(char *vg_args, char *clustername)
|
static int cluster_name_from_args(char *vg_args, char *clustername)
|
||||||
{
|
{
|
||||||
return last_string_from_args(vg_args, clustername);
|
return last_string_from_args(vg_args, clustername);
|
||||||
@@ -159,13 +160,9 @@ int lm_prepare_lockspace_dlm(struct lockspace *ls)
|
|||||||
{
|
{
|
||||||
char sys_clustername[MAX_ARGS+1];
|
char sys_clustername[MAX_ARGS+1];
|
||||||
char arg_clustername[MAX_ARGS+1];
|
char arg_clustername[MAX_ARGS+1];
|
||||||
uint32_t major = 0, minor = 0, patch = 0;
|
|
||||||
struct lm_dlm *lmd;
|
struct lm_dlm *lmd;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
if (daemon_test)
|
|
||||||
goto skip_args;
|
|
||||||
|
|
||||||
memset(sys_clustername, 0, sizeof(sys_clustername));
|
memset(sys_clustername, 0, sizeof(sys_clustername));
|
||||||
memset(arg_clustername, 0, sizeof(arg_clustername));
|
memset(arg_clustername, 0, sizeof(arg_clustername));
|
||||||
|
|
||||||
@@ -173,17 +170,6 @@ int lm_prepare_lockspace_dlm(struct lockspace *ls)
|
|||||||
if (rv < 0)
|
if (rv < 0)
|
||||||
return -EMANAGER;
|
return -EMANAGER;
|
||||||
|
|
||||||
rv = dlm_kernel_version(&major, &minor, &patch);
|
|
||||||
if (rv < 0) {
|
|
||||||
log_error("prepare_lockspace_dlm kernel_version not detected %d", rv);
|
|
||||||
dlm_has_lvb_bug = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((major == 6) && (minor == 0) && (patch == 1)) {
|
|
||||||
log_debug("dlm kernel version %u.%u.%u has lvb bug", major, minor, patch);
|
|
||||||
dlm_has_lvb_bug = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ls->vg_args[0]) {
|
if (!ls->vg_args[0]) {
|
||||||
/* global lockspace has no vg args */
|
/* global lockspace has no vg args */
|
||||||
goto skip_args;
|
goto skip_args;
|
||||||
@@ -260,6 +246,10 @@ int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg)
|
|||||||
out:
|
out:
|
||||||
free(lmd);
|
free(lmd);
|
||||||
ls->lm_data = NULL;
|
ls->lm_data = NULL;
|
||||||
|
|
||||||
|
if (!strcmp(ls->name, gl_lsname_dlm))
|
||||||
|
gl_running_dlm = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,7 +333,7 @@ static int to_dlm_mode(int ld_mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||||
struct val_blk *vb_out)
|
uint32_t *r_version)
|
||||||
{
|
{
|
||||||
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
||||||
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
||||||
@@ -352,7 +342,7 @@ static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
|||||||
int mode;
|
int mode;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
memset(vb_out, 0, sizeof(struct val_blk));
|
*r_version = 0;
|
||||||
|
|
||||||
if (!r->lm_init) {
|
if (!r->lm_init) {
|
||||||
rv = lm_add_resource_dlm(ls, r, 0);
|
rv = lm_add_resource_dlm(ls, r, 0);
|
||||||
@@ -394,7 +384,7 @@ static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
|||||||
(void *)1, (void *)1, (void *)1,
|
(void *)1, (void *)1, (void *)1,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
|
|
||||||
if (rv == -1 && errno == -EAGAIN) {
|
if (rv == -EAGAIN) {
|
||||||
log_debug("S %s R %s adopt_dlm adopt mode %d try other mode",
|
log_debug("S %s R %s adopt_dlm adopt mode %d try other mode",
|
||||||
ls->name, r->name, ld_mode);
|
ls->name, r->name, ld_mode);
|
||||||
rv = -EUCLEAN;
|
rv = -EUCLEAN;
|
||||||
@@ -431,13 +421,14 @@ static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||||
struct val_blk *vb_out, int adopt)
|
uint32_t *r_version, int adopt)
|
||||||
{
|
{
|
||||||
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
||||||
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
||||||
struct dlm_lksb *lksb;
|
struct dlm_lksb *lksb;
|
||||||
struct val_blk vb;
|
struct val_blk vb;
|
||||||
uint32_t flags = 0;
|
uint32_t flags = 0;
|
||||||
|
uint16_t vb_version;
|
||||||
int mode;
|
int mode;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
@@ -445,7 +436,7 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
|||||||
/* When adopting, we don't follow the normal method
|
/* When adopting, we don't follow the normal method
|
||||||
of acquiring a NL lock then converting it to the
|
of acquiring a NL lock then converting it to the
|
||||||
desired mode. */
|
desired mode. */
|
||||||
return lm_adopt_dlm(ls, r, ld_mode, vb_out);
|
return lm_adopt_dlm(ls, r, ld_mode, r_version);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!r->lm_init) {
|
if (!r->lm_init) {
|
||||||
@@ -473,41 +464,19 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
|||||||
log_debug("S %s R %s lock_dlm", ls->name, r->name);
|
log_debug("S %s R %s lock_dlm", ls->name, r->name);
|
||||||
|
|
||||||
if (daemon_test) {
|
if (daemon_test) {
|
||||||
if (rdd->vb) {
|
*r_version = 0;
|
||||||
vb_out->version = le16_to_cpu(rdd->vb->version);
|
|
||||||
vb_out->flags = le16_to_cpu(rdd->vb->flags);
|
|
||||||
vb_out->r_version = le32_to_cpu(rdd->vb->r_version);
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* The dlm lvb bug means that converting NL->EX will not return
|
|
||||||
* the latest lvb, so we have to convert NL->PR->EX to reread it.
|
|
||||||
*/
|
|
||||||
if (dlm_has_lvb_bug && (ld_mode == LD_LK_EX)) {
|
|
||||||
rv = dlm_ls_lock_wait(lmd->dh, LKM_PRMODE, lksb, flags,
|
|
||||||
r->name, strlen(r->name),
|
|
||||||
0, NULL, NULL, NULL);
|
|
||||||
if (rv == -1) {
|
|
||||||
log_debug("S %s R %s lock_dlm acquire mode PR for %d rv %d",
|
|
||||||
ls->name, r->name, mode, rv);
|
|
||||||
goto lockrv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fall through to request EX. */
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = dlm_ls_lock_wait(lmd->dh, mode, lksb, flags,
|
rv = dlm_ls_lock_wait(lmd->dh, mode, lksb, flags,
|
||||||
r->name, strlen(r->name),
|
r->name, strlen(r->name),
|
||||||
0, NULL, NULL, NULL);
|
0, NULL, NULL, NULL);
|
||||||
lockrv:
|
if (rv == -EAGAIN) {
|
||||||
if (rv == -1 && errno == EAGAIN) {
|
log_error("S %s R %s lock_dlm mode %d rv EAGAIN", ls->name, r->name, mode);
|
||||||
log_debug("S %s R %s lock_dlm acquire mode %d rv EAGAIN", ls->name, r->name, mode);
|
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
log_error("S %s R %s lock_dlm acquire error %d errno %d", ls->name, r->name, rv, errno);
|
log_error("S %s R %s lock_dlm error %d", ls->name, r->name, rv);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -515,22 +484,28 @@ lockrv:
|
|||||||
if (lksb->sb_flags & DLM_SBF_VALNOTVALID) {
|
if (lksb->sb_flags & DLM_SBF_VALNOTVALID) {
|
||||||
log_debug("S %s R %s lock_dlm VALNOTVALID", ls->name, r->name);
|
log_debug("S %s R %s lock_dlm VALNOTVALID", ls->name, r->name);
|
||||||
memset(rdd->vb, 0, sizeof(struct val_blk));
|
memset(rdd->vb, 0, sizeof(struct val_blk));
|
||||||
memset(vb_out, 0, sizeof(struct val_blk));
|
*r_version = 0;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* 'vb' contains disk endian values, not host endian.
|
|
||||||
* It is copied directly to rdd->vb which is also kept
|
|
||||||
* in disk endian form.
|
|
||||||
* vb_out is returned to the caller in host endian form.
|
|
||||||
*/
|
|
||||||
memcpy(&vb, lksb->sb_lvbptr, sizeof(struct val_blk));
|
memcpy(&vb, lksb->sb_lvbptr, sizeof(struct val_blk));
|
||||||
memcpy(rdd->vb, &vb, sizeof(vb));
|
vb_version = le16_to_cpu(vb.version);
|
||||||
|
|
||||||
vb_out->version = le16_to_cpu(vb.version);
|
if (vb_version && ((vb_version & 0xFF00) > (VAL_BLK_VERSION & 0xFF00))) {
|
||||||
vb_out->flags = le16_to_cpu(vb.flags);
|
log_error("S %s R %s lock_dlm ignore vb_version %x",
|
||||||
vb_out->r_version = le32_to_cpu(vb.r_version);
|
ls->name, r->name, vb_version);
|
||||||
|
*r_version = 0;
|
||||||
|
free(rdd->vb);
|
||||||
|
rdd->vb = NULL;
|
||||||
|
lksb->sb_lvbptr = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
*r_version = le32_to_cpu(vb.r_version);
|
||||||
|
memcpy(rdd->vb, &vb, sizeof(vb)); /* rdd->vb saved as le */
|
||||||
|
|
||||||
|
log_debug("S %s R %s lock_dlm get r_version %u",
|
||||||
|
ls->name, r->name, *r_version);
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
return 0;
|
return 0;
|
||||||
@@ -574,7 +549,7 @@ int lm_convert_dlm(struct lockspace *ls, struct resource *r,
|
|||||||
rv = dlm_ls_lock_wait(lmd->dh, mode, lksb, flags,
|
rv = dlm_ls_lock_wait(lmd->dh, mode, lksb, flags,
|
||||||
r->name, strlen(r->name),
|
r->name, strlen(r->name),
|
||||||
0, NULL, NULL, NULL);
|
0, NULL, NULL, NULL);
|
||||||
if (rv == -1 && errno == EAGAIN) {
|
if (rv == -EAGAIN) {
|
||||||
/* FIXME: When does this happen? Should something different be done? */
|
/* FIXME: When does this happen? Should something different be done? */
|
||||||
log_error("S %s R %s convert_dlm mode %d rv EAGAIN", ls->name, r->name, mode);
|
log_error("S %s R %s convert_dlm mode %d rv EAGAIN", ls->name, r->name, mode);
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
@@ -586,17 +561,17 @@ int lm_convert_dlm(struct lockspace *ls, struct resource *r,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
||||||
uint32_t r_version, uint32_t lmu_flags)
|
uint32_t r_version, uint32_t lmuf_flags)
|
||||||
{
|
{
|
||||||
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
||||||
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
||||||
struct dlm_lksb *lksb = &rdd->lksb;
|
struct dlm_lksb *lksb = &rdd->lksb;
|
||||||
struct val_blk vb_prev;
|
|
||||||
struct val_blk vb_next;
|
|
||||||
uint32_t flags = 0;
|
uint32_t flags = 0;
|
||||||
int new_vb = 0;
|
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
|
log_debug("S %s R %s unlock_dlm r_version %u flags %x",
|
||||||
|
ls->name, r->name, r_version, lmuf_flags);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do not set PERSISTENT, because we don't need an orphan
|
* Do not set PERSISTENT, because we don't need an orphan
|
||||||
* NL lock to protect anything.
|
* NL lock to protect anything.
|
||||||
@@ -604,46 +579,19 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
|||||||
|
|
||||||
flags |= LKF_CONVERT;
|
flags |= LKF_CONVERT;
|
||||||
|
|
||||||
if (rdd->vb && (r->mode == LD_LK_EX)) {
|
if (rdd->vb && r_version && (r->mode == LD_LK_EX)) {
|
||||||
|
if (!rdd->vb->version) {
|
||||||
/* vb_prev and vb_next are in disk endian form */
|
/* first time vb has been written */
|
||||||
memcpy(&vb_prev, rdd->vb, sizeof(struct val_blk));
|
rdd->vb->version = cpu_to_le16(VAL_BLK_VERSION);
|
||||||
memcpy(&vb_next, rdd->vb, sizeof(struct val_blk));
|
|
||||||
|
|
||||||
if (!vb_prev.version) {
|
|
||||||
vb_next.version = cpu_to_le16(VAL_BLK_VERSION);
|
|
||||||
new_vb = 1;
|
|
||||||
}
|
}
|
||||||
|
if (r_version)
|
||||||
|
rdd->vb->r_version = cpu_to_le32(r_version);
|
||||||
|
memcpy(lksb->sb_lvbptr, rdd->vb, sizeof(struct val_blk));
|
||||||
|
|
||||||
if ((lmu_flags & LMUF_FREE_VG) && (r->type == LD_RT_VG)) {
|
log_debug("S %s R %s unlock_dlm set r_version %u",
|
||||||
vb_next.flags = cpu_to_le16(VBF_REMOVED);
|
ls->name, r->name, r_version);
|
||||||
new_vb = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r_version) {
|
|
||||||
vb_next.r_version = cpu_to_le32(r_version);
|
|
||||||
new_vb = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (new_vb) {
|
|
||||||
memcpy(rdd->vb, &vb_next, sizeof(struct val_blk));
|
|
||||||
memcpy(lksb->sb_lvbptr, &vb_next, sizeof(struct val_blk));
|
|
||||||
|
|
||||||
log_debug("S %s R %s unlock_dlm vb old %x %x %u new %x %x %u",
|
|
||||||
ls->name, r->name,
|
|
||||||
le16_to_cpu(vb_prev.version),
|
|
||||||
le16_to_cpu(vb_prev.flags),
|
|
||||||
le32_to_cpu(vb_prev.r_version),
|
|
||||||
le16_to_cpu(vb_next.version),
|
|
||||||
le16_to_cpu(vb_next.flags),
|
|
||||||
le32_to_cpu(vb_next.r_version));
|
|
||||||
} else {
|
|
||||||
log_debug("S %s R %s unlock_dlm vb unchanged", ls->name, r->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
flags |= LKF_VALBLK;
|
flags |= LKF_VALBLK;
|
||||||
} else {
|
|
||||||
log_debug("S %s R %s unlock_dlm", ls->name, r->name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (daemon_test)
|
if (daemon_test)
|
||||||
@@ -666,65 +614,6 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
|||||||
|
|
||||||
#define DLM_LOCKSPACES_PATH "/sys/kernel/config/dlm/cluster/spaces"
|
#define DLM_LOCKSPACES_PATH "/sys/kernel/config/dlm/cluster/spaces"
|
||||||
|
|
||||||
/*
|
|
||||||
* FIXME: this should be implemented differently.
|
|
||||||
* It's not nice to use an aspect of the dlm clustering
|
|
||||||
* implementation, which could change. It would be
|
|
||||||
* better to do something like use a special lock in the
|
|
||||||
* lockspace that was held PR by all nodes, and then an
|
|
||||||
* EX request on it could check if it's started (and
|
|
||||||
* possibly also notify others to stop it automatically).
|
|
||||||
* Or, possibly an enhancement to libdlm that would give
|
|
||||||
* info about lockspace members.
|
|
||||||
*
|
|
||||||
* (We could let the VG be removed while others still
|
|
||||||
* have the lockspace running, which largely works, but
|
|
||||||
* introduces problems if another VG with the same name is
|
|
||||||
* recreated while others still have the lockspace running
|
|
||||||
* for the previous VG. We'd also want a way to clean up
|
|
||||||
* the stale lockspaces on the others eventually.)
|
|
||||||
*/
|
|
||||||
|
|
||||||
int lm_hosts_dlm(struct lockspace *ls, int notify)
|
|
||||||
{
|
|
||||||
static const char closedir_err_msg[] = "lm_hosts_dlm: closedir failed";
|
|
||||||
char ls_nodes_path[PATH_MAX];
|
|
||||||
struct dirent *de;
|
|
||||||
DIR *ls_dir;
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
if (daemon_test)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
memset(ls_nodes_path, 0, sizeof(ls_nodes_path));
|
|
||||||
snprintf(ls_nodes_path, PATH_MAX-1, "%s/%s/nodes",
|
|
||||||
DLM_LOCKSPACES_PATH, ls->name);
|
|
||||||
|
|
||||||
if (!(ls_dir = opendir(ls_nodes_path)))
|
|
||||||
return -ECONNREFUSED;
|
|
||||||
|
|
||||||
while ((de = readdir(ls_dir))) {
|
|
||||||
if (de->d_name[0] == '.')
|
|
||||||
continue;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (closedir(ls_dir))
|
|
||||||
log_error(closedir_err_msg);
|
|
||||||
|
|
||||||
if (!count) {
|
|
||||||
log_error("lm_hosts_dlm found no nodes in %s", ls_nodes_path);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Assume that a count of one node represents ourself,
|
|
||||||
* and any value over one represents other nodes.
|
|
||||||
*/
|
|
||||||
|
|
||||||
return count - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
|
int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
|
||||||
{
|
{
|
||||||
static const char closedir_err_msg[] = "lm_get_lockspace_dlm: closedir failed";
|
static const char closedir_err_msg[] = "lm_get_lockspace_dlm: closedir failed";
|
||||||
@@ -764,9 +653,6 @@ int lm_is_running_dlm(void)
|
|||||||
char sys_clustername[MAX_ARGS+1];
|
char sys_clustername[MAX_ARGS+1];
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
if (daemon_test)
|
|
||||||
return gl_use_dlm;
|
|
||||||
|
|
||||||
memset(sys_clustername, 0, sizeof(sys_clustername));
|
memset(sys_clustername, 0, sizeof(sys_clustername));
|
||||||
|
|
||||||
rv = read_cluster_name(sys_clustername);
|
rv = read_cluster_name(sys_clustername);
|
||||||
@@ -774,4 +660,3 @@ int lm_is_running_dlm(void)
|
|||||||
return 0;
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,9 +50,9 @@ enum {
|
|||||||
LD_OP_RENAME_FINAL,
|
LD_OP_RENAME_FINAL,
|
||||||
LD_OP_RUNNING_LM,
|
LD_OP_RUNNING_LM,
|
||||||
LD_OP_FIND_FREE_LOCK,
|
LD_OP_FIND_FREE_LOCK,
|
||||||
|
LD_OP_FORGET_VG_NAME,
|
||||||
LD_OP_KILL_VG,
|
LD_OP_KILL_VG,
|
||||||
LD_OP_DROP_VG,
|
LD_OP_DROP_VG,
|
||||||
LD_OP_BUSY,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* resource types */
|
/* resource types */
|
||||||
@@ -85,12 +85,11 @@ struct client {
|
|||||||
unsigned int recv : 1;
|
unsigned int recv : 1;
|
||||||
unsigned int dead : 1;
|
unsigned int dead : 1;
|
||||||
unsigned int poll_ignore : 1;
|
unsigned int poll_ignore : 1;
|
||||||
unsigned int lock_ops : 1;
|
|
||||||
char name[MAX_NAME+1];
|
char name[MAX_NAME+1];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define LD_AF_PERSISTENT 0x00000001
|
#define LD_AF_PERSISTENT 0x00000001
|
||||||
#define LD_AF_NO_CLIENT 0x00000002
|
#define LD_AF_UNUSED 0x00000002 /* use me */
|
||||||
#define LD_AF_UNLOCK_CANCEL 0x00000004
|
#define LD_AF_UNLOCK_CANCEL 0x00000004
|
||||||
#define LD_AF_NEXT_VERSION 0x00000008
|
#define LD_AF_NEXT_VERSION 0x00000008
|
||||||
#define LD_AF_WAIT 0x00000010
|
#define LD_AF_WAIT 0x00000010
|
||||||
@@ -101,10 +100,10 @@ struct client {
|
|||||||
#define LD_AF_SEARCH_LS 0x00000200
|
#define LD_AF_SEARCH_LS 0x00000200
|
||||||
#define LD_AF_WAIT_STARTING 0x00001000
|
#define LD_AF_WAIT_STARTING 0x00001000
|
||||||
#define LD_AF_DUP_GL_LS 0x00002000
|
#define LD_AF_DUP_GL_LS 0x00002000
|
||||||
|
#define LD_AF_INACTIVE_LS 0x00004000
|
||||||
|
#define LD_AF_ADD_LS_ERROR 0x00008000
|
||||||
#define LD_AF_ADOPT 0x00010000
|
#define LD_AF_ADOPT 0x00010000
|
||||||
#define LD_AF_WARN_GL_REMOVED 0x00020000
|
#define LD_AF_WARN_GL_REMOVED 0x00020000
|
||||||
#define LD_AF_LV_LOCK 0x00040000
|
|
||||||
#define LD_AF_LV_UNLOCK 0x00080000
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Number of times to repeat a lock request after
|
* Number of times to repeat a lock request after
|
||||||
@@ -143,13 +142,12 @@ struct resource {
|
|||||||
int8_t mode;
|
int8_t mode;
|
||||||
unsigned int sh_count; /* number of sh locks on locks list */
|
unsigned int sh_count; /* number of sh locks on locks list */
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
uint32_t last_client_id; /* last client_id to lock or unlock resource */
|
|
||||||
unsigned int lm_init : 1; /* lm_data is initialized */
|
unsigned int lm_init : 1; /* lm_data is initialized */
|
||||||
unsigned int adopt : 1; /* temp flag in remove_inactive_lvs */
|
unsigned int adopt : 1; /* temp flag in remove_inactive_lvs */
|
||||||
unsigned int version_zero_valid : 1;
|
unsigned int version_zero_valid : 1;
|
||||||
unsigned int use_vb : 1;
|
|
||||||
struct list_head locks;
|
struct list_head locks;
|
||||||
struct list_head actions;
|
struct list_head actions;
|
||||||
|
struct val_blk *vb;
|
||||||
char lv_args[MAX_ARGS+1];
|
char lv_args[MAX_ARGS+1];
|
||||||
char lm_data[0]; /* lock manager specific data */
|
char lm_data[0]; /* lock manager specific data */
|
||||||
};
|
};
|
||||||
@@ -195,12 +193,8 @@ struct lockspace {
|
|||||||
struct list_head resources; /* resource/lock state for gl/vg/lv */
|
struct list_head resources; /* resource/lock state for gl/vg/lv */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* val_blk version */
|
|
||||||
#define VAL_BLK_VERSION 0x0101
|
#define VAL_BLK_VERSION 0x0101
|
||||||
|
|
||||||
/* val_blk flags */
|
|
||||||
#define VBF_REMOVED 0x0001
|
|
||||||
|
|
||||||
struct val_blk {
|
struct val_blk {
|
||||||
uint16_t version;
|
uint16_t version;
|
||||||
uint16_t flags;
|
uint16_t flags;
|
||||||
@@ -317,12 +311,14 @@ static inline int list_empty(const struct list_head *head)
|
|||||||
* or when disable_gl matches.
|
* or when disable_gl matches.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
EXTERN int gl_running_dlm;
|
||||||
EXTERN int gl_type_static;
|
EXTERN int gl_type_static;
|
||||||
EXTERN int gl_use_dlm;
|
EXTERN int gl_use_dlm;
|
||||||
EXTERN int gl_use_sanlock;
|
EXTERN int gl_use_sanlock;
|
||||||
|
EXTERN pthread_mutex_t gl_type_mutex;
|
||||||
|
|
||||||
EXTERN char gl_lsname_dlm[MAX_NAME+1];
|
EXTERN char gl_lsname_dlm[MAX_NAME+1];
|
||||||
EXTERN char gl_lsname_sanlock[MAX_NAME+1];
|
EXTERN char gl_lsname_sanlock[MAX_NAME+1];
|
||||||
EXTERN int global_dlm_lockspace_exists;
|
|
||||||
|
|
||||||
EXTERN int daemon_test; /* run as much as possible without a live lock manager */
|
EXTERN int daemon_test; /* run as much as possible without a live lock manager */
|
||||||
EXTERN int daemon_debug;
|
EXTERN int daemon_debug;
|
||||||
@@ -351,23 +347,6 @@ int lockspaces_empty(void);
|
|||||||
int last_string_from_args(char *args_in, char *last);
|
int last_string_from_args(char *args_in, char *last);
|
||||||
int version_from_args(char *args, unsigned int *major, unsigned int *minor, unsigned int *patch);
|
int version_from_args(char *args, unsigned int *major, unsigned int *minor, unsigned int *patch);
|
||||||
|
|
||||||
static inline const char *mode_str(int x)
|
|
||||||
{
|
|
||||||
switch (x) {
|
|
||||||
case LD_LK_IV:
|
|
||||||
return "iv";
|
|
||||||
case LD_LK_UN:
|
|
||||||
return "un";
|
|
||||||
case LD_LK_NL:
|
|
||||||
return "nl";
|
|
||||||
case LD_LK_SH:
|
|
||||||
return "sh";
|
|
||||||
case LD_LK_EX:
|
|
||||||
return "ex";
|
|
||||||
default:
|
|
||||||
return ".";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef LOCKDDLM_SUPPORT
|
#ifdef LOCKDDLM_SUPPORT
|
||||||
|
|
||||||
@@ -376,7 +355,7 @@ int lm_prepare_lockspace_dlm(struct lockspace *ls);
|
|||||||
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt);
|
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt);
|
||||||
int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg);
|
int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg);
|
||||||
int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||||
struct val_blk *vb_out, int adopt);
|
uint32_t *r_version, int adopt);
|
||||||
int lm_convert_dlm(struct lockspace *ls, struct resource *r,
|
int lm_convert_dlm(struct lockspace *ls, struct resource *r,
|
||||||
int ld_mode, uint32_t r_version);
|
int ld_mode, uint32_t r_version);
|
||||||
int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
||||||
@@ -385,7 +364,6 @@ int lm_rem_resource_dlm(struct lockspace *ls, struct resource *r);
|
|||||||
int lm_get_lockspaces_dlm(struct list_head *ls_rejoin);
|
int lm_get_lockspaces_dlm(struct list_head *ls_rejoin);
|
||||||
int lm_data_size_dlm(void);
|
int lm_data_size_dlm(void);
|
||||||
int lm_is_running_dlm(void);
|
int lm_is_running_dlm(void);
|
||||||
int lm_hosts_dlm(struct lockspace *ls, int notify);
|
|
||||||
|
|
||||||
static inline int lm_support_dlm(void)
|
static inline int lm_support_dlm(void)
|
||||||
{
|
{
|
||||||
@@ -415,7 +393,7 @@ static inline int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
static inline int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||||
struct val_blk *vb_out, int adopt)
|
uint32_t *r_version, int adopt)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -457,11 +435,6 @@ static inline int lm_support_dlm(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int lm_hosts_dlm(struct lockspace *ls, int notify)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* dlm support */
|
#endif /* dlm support */
|
||||||
|
|
||||||
#ifdef LOCKDSANLOCK_SUPPORT
|
#ifdef LOCKDSANLOCK_SUPPORT
|
||||||
@@ -474,7 +447,7 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls);
|
|||||||
int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt);
|
int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt);
|
||||||
int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg);
|
int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg);
|
||||||
int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||||
struct val_blk *vb_out, int *retry, int adopt);
|
uint32_t *r_version, int *retry, int adopt);
|
||||||
int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
|
int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
|
||||||
int ld_mode, uint32_t r_version);
|
int ld_mode, uint32_t r_version);
|
||||||
int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
|
int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
|
||||||
@@ -532,7 +505,7 @@ static inline int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
static inline int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||||
struct val_blk *vb_out, int *retry, int adopt)
|
uint32_t *r_version, int *retry, int adopt)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user