mirror of
git://sourceware.org/git/lvm2.git
synced 2026-01-09 20:32:46 +03:00
Compare commits
319 Commits
v2_02_130
...
dev-mcsont
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf06d942b8 | ||
|
|
83d3cc76f3 | ||
|
|
89574055f7 | ||
|
|
7831a65091 | ||
|
|
15a97cc610 | ||
|
|
3f1c63c812 | ||
|
|
dd52721b68 | ||
|
|
7f125c1116 | ||
|
|
5b04eda93f | ||
|
|
77c31d0c39 | ||
|
|
baf320455b | ||
|
|
bb4d3fa7a7 | ||
|
|
3e18b101a0 | ||
|
|
df190dcfa5 | ||
|
|
e149fe7fdf | ||
|
|
77605457e7 | ||
|
|
0d5b1294f0 | ||
|
|
097d14e64e | ||
|
|
17196103e0 | ||
|
|
ccfc09f79b | ||
|
|
9a3b64e81a | ||
|
|
c2e88d1107 | ||
|
|
406d8ff332 | ||
|
|
00348c0a63 | ||
|
|
ccb8da404d | ||
|
|
28e54032c0 | ||
|
|
bca55c9b20 | ||
|
|
f104a81932 | ||
|
|
3720eb63be | ||
|
|
8b5525383f | ||
|
|
f58c634103 | ||
|
|
175119fdcd | ||
|
|
33a8a2febf | ||
|
|
f32f0bd2a7 | ||
|
|
99237f0908 | ||
|
|
099466939e | ||
|
|
b3c81d02c9 | ||
|
|
5886ff64eb | ||
|
|
a4418b34c1 | ||
|
|
65ec00ce20 | ||
|
|
6e1e0e8813 | ||
|
|
4159680a0e | ||
|
|
76cff10a73 | ||
|
|
1af2ab10d0 | ||
|
|
729f489009 | ||
|
|
5d76bdcdbd | ||
|
|
3b5939bbbb | ||
|
|
a2dd1f6e19 | ||
|
|
c301cc5d38 | ||
|
|
ba41ee1dc9 | ||
|
|
b702d67747 | ||
|
|
44ba862674 | ||
|
|
6624833839 | ||
|
|
b29593378f | ||
|
|
428ca9b120 | ||
|
|
f898cf7539 | ||
|
|
844b009584 | ||
|
|
9ef820a2a5 | ||
|
|
40eea582ae | ||
|
|
b780d329aa | ||
|
|
8f269697d2 | ||
|
|
98d81a43ea | ||
|
|
1a74171ca5 | ||
|
|
51735f09f7 | ||
|
|
3a42c13ccf | ||
|
|
8b965bd3d5 | ||
|
|
1a7bea0f0f | ||
|
|
b5b2a54834 | ||
|
|
21748a8630 | ||
|
|
e5b686d693 | ||
|
|
87a39d8bac | ||
|
|
cff1c728d8 | ||
|
|
2786cd27da | ||
|
|
1a2d0a0c72 | ||
|
|
b1319e0402 | ||
|
|
8be60e6a65 | ||
|
|
39cffa4e9b | ||
|
|
2af696c32f | ||
|
|
4284ba65eb | ||
|
|
aeec62ad19 | ||
|
|
12aa56d298 | ||
|
|
9156c5d088 | ||
|
|
466a1c72b7 | ||
|
|
81e9ab3156 | ||
|
|
15dbd4b56a | ||
|
|
e2ea2a8147 | ||
|
|
941c6354db | ||
|
|
02eb000f51 | ||
|
|
efc76ca33d | ||
|
|
590091a4fa | ||
|
|
9488cbdd0b | ||
|
|
fa9e41d2e3 | ||
|
|
6b0bc5b2d9 | ||
|
|
7ff5b03e5e | ||
|
|
91350f5c6a | ||
|
|
9c5c9e2355 | ||
|
|
cde12cbe9e | ||
|
|
ab6d16a8a5 | ||
|
|
09a62cca0c | ||
|
|
075f85dcb5 | ||
|
|
d2c4ce254b | ||
|
|
7b78d496bf | ||
|
|
19e272ba53 | ||
|
|
73e679f33f | ||
|
|
a0d819172f | ||
|
|
0aee04288e | ||
|
|
ef4d69f456 | ||
|
|
c15649b3af | ||
|
|
f67a52677b | ||
|
|
392248186e | ||
|
|
33465066c5 | ||
|
|
a5c4c4efbd | ||
|
|
83d475626a | ||
|
|
1ea7e2634d | ||
|
|
23d9b17a7b | ||
|
|
c3bfe07f2a | ||
|
|
508f0f5a21 | ||
|
|
df34fcdafd | ||
|
|
a6d1c8ac65 | ||
|
|
7c36d7c90c | ||
|
|
bbef4edd06 | ||
|
|
3f1a3b7090 | ||
|
|
a91fbe9d27 | ||
|
|
ccc39be053 | ||
|
|
0cf787a377 | ||
|
|
acc70de439 | ||
|
|
cf1c2da836 | ||
|
|
c4cc5eabfe | ||
|
|
8cc21354c2 | ||
|
|
2cb1f6eafe | ||
|
|
9322918406 | ||
|
|
83f00e9156 | ||
|
|
4f9e7f692e | ||
|
|
4b586ad3c2 | ||
|
|
256e432e78 | ||
|
|
51ff7d5ed8 | ||
|
|
49e11102c7 | ||
|
|
a11cd2ca2d | ||
|
|
f9926e7e6c | ||
|
|
76ea01dd20 | ||
|
|
362558cd66 | ||
|
|
09a8479cb7 | ||
|
|
0a633750f1 | ||
|
|
0e2261dbd1 | ||
|
|
842a7a17e3 | ||
|
|
f4fb97c850 | ||
|
|
8b9533f38f | ||
|
|
903e9af1b2 | ||
|
|
e261af52eb | ||
|
|
3f03d46fc1 | ||
|
|
0e27210308 | ||
|
|
13086c2523 | ||
|
|
42a9c8b4a6 | ||
|
|
e50583d721 | ||
|
|
c90363b585 | ||
|
|
915f0faac1 | ||
|
|
0641e3a5fd | ||
|
|
11a084cf42 | ||
|
|
d60794c3a3 | ||
|
|
1b1c01a27b | ||
|
|
72d700b064 | ||
|
|
86b04ebd19 | ||
|
|
7e1c08bb6a | ||
|
|
c7b4359ff4 | ||
|
|
5695c6aca6 | ||
|
|
5ac81657e5 | ||
|
|
5bd63df237 | ||
|
|
75420282e1 | ||
|
|
38df48d108 | ||
|
|
21a8ac0cd3 | ||
|
|
1f30ba6178 | ||
|
|
8733a8d890 | ||
|
|
5446d17756 | ||
|
|
c9ff5c8223 | ||
|
|
d99dd4086d | ||
|
|
09981afc1c | ||
|
|
3d03e504cd | ||
|
|
e04424e87e | ||
|
|
277dd0aa7a | ||
|
|
ded9452174 | ||
|
|
4b1cadbd87 | ||
|
|
2506275c3b | ||
|
|
5f7a94a03e | ||
|
|
df59db6048 | ||
|
|
b33d7586e7 | ||
|
|
fb957ef322 | ||
|
|
5e5d48348b | ||
|
|
26da6a3e10 | ||
|
|
4c2cc782aa | ||
|
|
05e7fdd5ce | ||
|
|
796e3fb7e4 | ||
|
|
867a36b419 | ||
|
|
a139275eca | ||
|
|
efcb3bbc8d | ||
|
|
309979d578 | ||
|
|
c805fa7c40 | ||
|
|
634bf8c953 | ||
|
|
be393f6722 | ||
|
|
d94ff20927 | ||
|
|
0173c260d8 | ||
|
|
9d815e5f5a | ||
|
|
7097663ddd | ||
|
|
eab099b221 | ||
|
|
3036620b48 | ||
|
|
d40830a2b1 | ||
|
|
028715b0f0 | ||
|
|
4a74e19f80 | ||
|
|
e773e71910 | ||
|
|
39a97d86f0 | ||
|
|
41fe225b0d | ||
|
|
1945a0f504 | ||
|
|
4e60e62444 | ||
|
|
96a6210198 | ||
|
|
192d9ad977 | ||
|
|
cb82919b0d | ||
|
|
28aff5d240 | ||
|
|
532b2d2d4e | ||
|
|
214e2cddf6 | ||
|
|
0ce150280e | ||
|
|
3a8a37187d | ||
|
|
629398d0f2 | ||
|
|
fd773dffb2 | ||
|
|
001f747963 | ||
|
|
2081071bee | ||
|
|
47f623d64b | ||
|
|
7e63364529 | ||
|
|
2e5bde4a77 | ||
|
|
cfe869692f | ||
|
|
a61f3c5316 | ||
|
|
ce80d73684 | ||
|
|
804c25a81a | ||
|
|
a54b4bba35 | ||
|
|
0a01c5aa36 | ||
|
|
f01b7afa19 | ||
|
|
ffa7b37b28 | ||
|
|
f61a394be4 | ||
|
|
c2ea5b3dee | ||
|
|
199697accf | ||
|
|
cb8f29d147 | ||
|
|
0e3042f488 | ||
|
|
f644431346 | ||
|
|
83a52c07b7 | ||
|
|
7d1dd5f52d | ||
|
|
330d584617 | ||
|
|
11d6f81316 | ||
|
|
f9c8cefd06 | ||
|
|
791e76ff70 | ||
|
|
e0d915a873 | ||
|
|
90ad817a43 | ||
|
|
5bc8c713e2 | ||
|
|
6c0b4a2769 | ||
|
|
afdae26c71 | ||
|
|
b5022102bb | ||
|
|
b7410c95cf | ||
|
|
fcfca57e2e | ||
|
|
0ac10bb23a | ||
|
|
a729b1aa29 | ||
|
|
548c09acfc | ||
|
|
2ce8ee0214 | ||
|
|
cee9ed2244 | ||
|
|
e7e15631dd | ||
|
|
ffeeb5c1e7 | ||
|
|
c356991fa8 | ||
|
|
e42ee69988 | ||
|
|
226e7d7b3c | ||
|
|
cd2e4310b3 | ||
|
|
fd3d795b93 | ||
|
|
729b035edd | ||
|
|
fda853b573 | ||
|
|
280a6275ce | ||
|
|
95b5d24f43 | ||
|
|
19443035a6 | ||
|
|
8b8103efef | ||
|
|
6bc3d72a65 | ||
|
|
854a559a49 | ||
|
|
18dfbbb150 | ||
|
|
0a26c20b88 | ||
|
|
0889cff5d5 | ||
|
|
9b8c876293 | ||
|
|
e94ab01940 | ||
|
|
54c982081f | ||
|
|
a631fa20d0 | ||
|
|
5911fa1d91 | ||
|
|
e1edb5676e | ||
|
|
3670f095c7 | ||
|
|
f11d690967 | ||
|
|
15ae237d2c | ||
|
|
36d16fed1f | ||
|
|
30e489db5e | ||
|
|
2296999cf6 | ||
|
|
d323acdfec | ||
|
|
81b0e9de7c | ||
|
|
587fd6a0e4 | ||
|
|
6cb7f21e38 | ||
|
|
8ff43c3705 | ||
|
|
026db90621 | ||
|
|
b77497cbd8 | ||
|
|
596ec5c74b | ||
|
|
0ec64370b2 | ||
|
|
d7f45ebca5 | ||
|
|
daa94eb792 | ||
|
|
5f990473e4 | ||
|
|
4bc7a86f3a | ||
|
|
ffbf12504d | ||
|
|
330cad1567 | ||
|
|
fa4d2ec241 | ||
|
|
acfc56957c | ||
|
|
3ba431e79e | ||
|
|
d62448cb45 | ||
|
|
1999e368f1 | ||
|
|
fc4f0d3fce | ||
|
|
9403edbb93 | ||
|
|
ab1b54c3e3 | ||
|
|
0f5933ecc1 | ||
|
|
e75b4bc2df | ||
|
|
36b09fd147 | ||
|
|
a26523330e | ||
|
|
2a022e9e6e | ||
|
|
fb12308416 |
14
Makefile.in
14
Makefile.in
@@ -131,6 +131,9 @@ rpm: dist
|
||||
generate: conf.generate
|
||||
$(MAKE) -C conf generate
|
||||
|
||||
all_man:
|
||||
$(MAKE) -C man all_man
|
||||
|
||||
install_system_dirs:
|
||||
$(INSTALL_DIR) $(DESTDIR)$(DEFAULT_SYS_DIR)
|
||||
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_ARCHIVE_DIR)
|
||||
@@ -150,8 +153,8 @@ install_systemd_generators:
|
||||
install_systemd_units:
|
||||
$(MAKE) -C scripts install_systemd_units
|
||||
|
||||
install_full_man:
|
||||
$(MAKE) -C man install_full_man
|
||||
install_all_man:
|
||||
$(MAKE) -C man install_all_man
|
||||
|
||||
ifeq ("@PYTHON_BINDINGS@", "yes")
|
||||
install_python_bindings:
|
||||
@@ -229,10 +232,9 @@ endif
|
||||
|
||||
ifneq ($(shell which ctags),)
|
||||
.PHONY: tags
|
||||
all: tags
|
||||
tags:
|
||||
test -z "$(shell find $(top_srcdir) -type f -name '*.[ch]' -newer tags | head -1)" || $(RM) tags
|
||||
test -f tags || find $(top_srcdir) -maxdepth 4 -type f -name '*.[ch]' -exec ctags -a '{}' +
|
||||
test -z "$(shell find $(top_srcdir) -type f -name '*.[ch]' -newer tags 2>/dev/null | head -1)" || $(RM) tags
|
||||
test -f tags || find $(top_srcdir) -maxdepth 5 -type f -name '*.[ch]' -exec ctags -a '{}' +
|
||||
|
||||
DISTCLEAN_TARGETS += tags
|
||||
CLEAN_TARGETS += tags
|
||||
endif
|
||||
|
||||
@@ -1 +1 @@
|
||||
1.02.107-git (2015-09-05)
|
||||
1.02.111-git (2015-10-30)
|
||||
|
||||
58
WHATS_NEW
58
WHATS_NEW
@@ -1,3 +1,61 @@
|
||||
Version 2.02.134 -
|
||||
====================================
|
||||
|
||||
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.
|
||||
|
||||
45
WHATS_NEW_DM
45
WHATS_NEW_DM
@@ -1,3 +1,48 @@
|
||||
Version 1.02.111 -
|
||||
====================================
|
||||
|
||||
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 2016
|
||||
======================================
|
||||
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.
|
||||
|
||||
2
aclocal.m4
vendored
2
aclocal.m4
vendored
@@ -15,7 +15,7 @@ m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun
|
||||
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||||
# serial 1 (pkg-config-0.24)
|
||||
#
|
||||
# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
|
||||
# Copyright (c) 2004 Scott James Remnant <scott@netsplit.com>.
|
||||
#
|
||||
# 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
|
||||
|
||||
2
conf/.gitignore
vendored
2
conf/.gitignore
vendored
@@ -2,3 +2,5 @@ command_profile_template.profile
|
||||
example.conf
|
||||
lvmlocal.conf
|
||||
metadata_profile_template.profile
|
||||
configure.h
|
||||
lvm-version.h
|
||||
|
||||
@@ -389,8 +389,8 @@ allocation {
|
||||
# This configuration option does not have a default value defined.
|
||||
|
||||
# Configuration section allocation/cache_settings.
|
||||
# Individual settings for policies.
|
||||
# See the help for individual policies for more info.
|
||||
# Settings for the cache policy.
|
||||
# See documentation for individual cache policies for more info.
|
||||
# This configuration section has an automatic default value.
|
||||
# cache_settings {
|
||||
# }
|
||||
@@ -1494,13 +1494,25 @@ activation {
|
||||
# report {
|
||||
|
||||
# Configuration option report/compact_output.
|
||||
# Do not print empty report fields.
|
||||
# Fields that don't have a value set for any of the rows reported are
|
||||
# skipped and not printed. Compact output is applicable only if
|
||||
# report/buffered is enabled.
|
||||
# Do not print empty values for all report fields.
|
||||
# If enabled, all fields that don't have a value set for any of the
|
||||
# rows reported are skipped and not printed. Compact output is
|
||||
# applicable only if report/buffered is enabled. If you need to
|
||||
# compact only specified fields, use compact_output=0 and define
|
||||
# report/compact_output_cols configuration setting instead.
|
||||
# This configuration option has an automatic default value.
|
||||
# compact_output = 0
|
||||
|
||||
# Configuration option report/compact_output_cols.
|
||||
# Do not print empty values for specified report fields.
|
||||
# If defined, specified fields that don't have a value set for any
|
||||
# of the rows reported are skipped and not printed. Compact output
|
||||
# is applicable only if report/buffered is enabled. If you need to
|
||||
# compact all fields, use compact_output=1 instead in which case
|
||||
# the compact_output_cols setting is then ignored.
|
||||
# This configuration option has an automatic default value.
|
||||
# compact_output_cols = ""
|
||||
|
||||
# Configuration option report/aligned.
|
||||
# Align columns in report output.
|
||||
# This configuration option has an automatic default value.
|
||||
|
||||
34
configure
vendored
34
configure
vendored
@@ -643,6 +643,7 @@ LVMETAD_PIDFILE
|
||||
DMEVENTD_PIDFILE
|
||||
WRITE_INSTALL
|
||||
VALGRIND_POOL
|
||||
USE_TRACKING
|
||||
UDEV_HAS_BUILTIN_BLKID
|
||||
UDEV_RULE_EXEC_DETECTION
|
||||
UDEV_SYSTEMD_BACKGROUND_JOBS
|
||||
@@ -693,7 +694,6 @@ BLKDEACTIVATE
|
||||
FSADM
|
||||
ELDFLAGS
|
||||
DM_LIB_PATCHLEVEL
|
||||
DM_LIB_VERSION
|
||||
DMEVENTD_PATH
|
||||
DMEVENTD
|
||||
DL_LIBS
|
||||
@@ -876,6 +876,7 @@ SHELL'
|
||||
ac_subst_files=''
|
||||
ac_user_opts='
|
||||
enable_option_checking
|
||||
enable_dependency_tracking
|
||||
enable_static_link
|
||||
with_user
|
||||
with_group
|
||||
@@ -1634,6 +1635,8 @@ Optional Features:
|
||||
--disable-option-checking ignore unrecognized --enable/--with options
|
||||
--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
|
||||
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
|
||||
--disable-dependency-tracking
|
||||
speeds up one-time build.
|
||||
--enable-static_link use this to link the tools to their libraries
|
||||
statically (default is dynamic linking
|
||||
--enable-lvm1_fallback use this to fall back and use LVM1 binaries if
|
||||
@@ -2966,7 +2969,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
||||
|
||||
|
||||
|
||||
ac_config_headers="$ac_config_headers lib/misc/configure.h"
|
||||
ac_config_headers="$ac_config_headers include/configure.h"
|
||||
|
||||
|
||||
################################################################################
|
||||
@@ -7632,6 +7635,19 @@ done
|
||||
|
||||
|
||||
|
||||
################################################################################
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable dependency tracking" >&5
|
||||
$as_echo_n "checking whether to enable dependency tracking... " >&6; }
|
||||
# Check whether --enable-dependency-tracking was given.
|
||||
if test "${enable_dependency_tracking+set}" = set; then :
|
||||
enableval=$enable_dependency_tracking; USE_TRACKING=$enableval
|
||||
else
|
||||
USE_TRACKING=yes
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_TRACKING" >&5
|
||||
$as_echo "$USE_TRACKING" >&6; }
|
||||
|
||||
################################################################################
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use static linking" >&5
|
||||
$as_echo_n "checking whether to use static linking... " >&6; }
|
||||
@@ -14026,18 +14042,18 @@ test "$interface" != ioctl && as_fn_error $? "--with-interface=ioctl required. f
|
||||
$as_echo "$interface" >&6; }
|
||||
|
||||
################################################################################
|
||||
DM_LIB_VERSION="\"`cat "$srcdir"/VERSION_DM 2>/dev/null || echo Unknown`\""
|
||||
read DM_LIB_VERSION < "$srcdir"/VERSION_DM 2>/dev/null || DM_LIB_VERSION=Unknown
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define DM_LIB_VERSION $DM_LIB_VERSION
|
||||
#define DM_LIB_VERSION "$DM_LIB_VERSION"
|
||||
_ACEOF
|
||||
|
||||
|
||||
DM_LIB_PATCHLEVEL=`cat "$srcdir"/VERSION_DM | $AWK -F '[-. ]' '{printf "%s.%s.%s",$1,$2,$3}'`
|
||||
|
||||
LVM_VERSION="\"`cat "$srcdir"/VERSION 2>/dev/null || echo Unknown`\""
|
||||
read VER < "$srcdir"/VERSION 2>/dev/null || VER=Unknown
|
||||
|
||||
VER=`cat "$srcdir"/VERSION`
|
||||
LVM_VERSION=\"$VER\"
|
||||
LVM_RELEASE_DATE="\"`echo $VER | $SED 's/.* (//;s/).*//'`\""
|
||||
VER=`echo "$VER" | $AWK '{print $1}'`
|
||||
LVM_RELEASE="\"`echo "$VER" | $AWK -F '-' '{print $2}'`\""
|
||||
@@ -14196,7 +14212,7 @@ LVM_LIBAPI=`echo "$VER" | $AWK -F '[()]' '{print $2}'`
|
||||
|
||||
|
||||
################################################################################
|
||||
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/lvmetad/Makefile daemons/lvmpolld/Makefile daemons/lvmlockd/Makefile conf/Makefile conf/example.conf conf/lvmlocal.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/replicator/Makefile lib/misc/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/Makefile lib/cache_segtype/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cluster_activation_red_hat.sh scripts/lvm2_cluster_activation_systemd_red_hat.service scripts/lvm2_clvmd_systemd_red_hat.service scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmpolld_init_red_hat scripts/lvm2_lvmpolld_systemd_red_hat.service scripts/lvm2_lvmpolld_systemd_red_hat.socket scripts/lvm2_lvmlockd_systemd_red_hat.service scripts/lvm2_lvmlocking_systemd_red_hat.service scripts/lvm2_monitoring_init_red_hat scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_tmpfiles_red_hat.conf scripts/Makefile test/Makefile test/api/Makefile test/unit/Makefile tools/Makefile udev/Makefile unit-tests/datastruct/Makefile unit-tests/regex/Makefile unit-tests/mm/Makefile"
|
||||
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/lvmetad/Makefile daemons/lvmpolld/Makefile daemons/lvmlockd/Makefile conf/Makefile conf/example.conf conf/lvmlocal.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/replicator/Makefile include/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/Makefile lib/cache_segtype/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cluster_activation_red_hat.sh scripts/lvm2_cluster_activation_systemd_red_hat.service scripts/lvm2_clvmd_systemd_red_hat.service scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmpolld_init_red_hat scripts/lvm2_lvmpolld_systemd_red_hat.service scripts/lvm2_lvmpolld_systemd_red_hat.socket scripts/lvm2_lvmlockd_systemd_red_hat.service scripts/lvm2_lvmlocking_systemd_red_hat.service scripts/lvm2_monitoring_init_red_hat scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_tmpfiles_red_hat.conf scripts/Makefile test/Makefile test/api/Makefile test/unit/Makefile tools/Makefile udev/Makefile unit-tests/datastruct/Makefile unit-tests/regex/Makefile unit-tests/mm/Makefile"
|
||||
|
||||
cat >confcache <<\_ACEOF
|
||||
# This file is a shell script that caches the results of configure
|
||||
@@ -14890,7 +14906,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||
for ac_config_target in $ac_config_targets
|
||||
do
|
||||
case $ac_config_target in
|
||||
"lib/misc/configure.h") CONFIG_HEADERS="$CONFIG_HEADERS lib/misc/configure.h" ;;
|
||||
"include/configure.h") CONFIG_HEADERS="$CONFIG_HEADERS include/configure.h" ;;
|
||||
"Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
|
||||
"make.tmpl") CONFIG_FILES="$CONFIG_FILES make.tmpl" ;;
|
||||
"daemons/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/Makefile" ;;
|
||||
@@ -14920,7 +14936,7 @@ do
|
||||
"lib/locking/Makefile") CONFIG_FILES="$CONFIG_FILES lib/locking/Makefile" ;;
|
||||
"lib/mirror/Makefile") CONFIG_FILES="$CONFIG_FILES lib/mirror/Makefile" ;;
|
||||
"lib/replicator/Makefile") CONFIG_FILES="$CONFIG_FILES lib/replicator/Makefile" ;;
|
||||
"lib/misc/lvm-version.h") CONFIG_FILES="$CONFIG_FILES lib/misc/lvm-version.h" ;;
|
||||
"include/lvm-version.h") CONFIG_FILES="$CONFIG_FILES include/lvm-version.h" ;;
|
||||
"lib/raid/Makefile") CONFIG_FILES="$CONFIG_FILES lib/raid/Makefile" ;;
|
||||
"lib/snapshot/Makefile") CONFIG_FILES="$CONFIG_FILES lib/snapshot/Makefile" ;;
|
||||
"lib/thin/Makefile") CONFIG_FILES="$CONFIG_FILES lib/thin/Makefile" ;;
|
||||
|
||||
23
configure.in
23
configure.in
@@ -16,7 +16,7 @@ AC_PREREQ(2.61)
|
||||
dnl -- Process this file with autoconf to produce a configure script.
|
||||
AC_INIT
|
||||
AC_CONFIG_SRCDIR([lib/device/dev-cache.h])
|
||||
AC_CONFIG_HEADERS([lib/misc/configure.h])
|
||||
AC_CONFIG_HEADERS([include/configure.h])
|
||||
|
||||
################################################################################
|
||||
dnl -- Setup the directory where autoconf has auxilary files
|
||||
@@ -155,6 +155,15 @@ AC_FUNC_STAT
|
||||
AC_FUNC_STRTOD
|
||||
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
|
||||
AC_MSG_CHECKING(whether to use static linking)
|
||||
@@ -1879,14 +1888,14 @@ test "$interface" != ioctl && AC_MSG_ERROR([--with-interface=ioctl required. fs
|
||||
AC_MSG_RESULT($interface)
|
||||
|
||||
################################################################################
|
||||
DM_LIB_VERSION="\"`cat "$srcdir"/VERSION_DM 2>/dev/null || echo Unknown`\""
|
||||
AC_DEFINE_UNQUOTED(DM_LIB_VERSION, $DM_LIB_VERSION, [Library version])
|
||||
read DM_LIB_VERSION < "$srcdir"/VERSION_DM 2>/dev/null || DM_LIB_VERSION=Unknown
|
||||
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}'`
|
||||
|
||||
LVM_VERSION="\"`cat "$srcdir"/VERSION 2>/dev/null || echo Unknown`\""
|
||||
read VER < "$srcdir"/VERSION 2>/dev/null || VER=Unknown
|
||||
|
||||
VER=`cat "$srcdir"/VERSION`
|
||||
LVM_VERSION=\"$VER\"
|
||||
LVM_RELEASE_DATE="\"`echo $VER | $SED 's/.* (//;s/).*//'`\""
|
||||
VER=`echo "$VER" | $AWK '{print $1}'`
|
||||
LVM_RELEASE="\"`echo "$VER" | $AWK -F '-' '{print $2}'`\""
|
||||
@@ -1954,7 +1963,6 @@ AC_SUBST(DLM_LIBS)
|
||||
AC_SUBST(DL_LIBS)
|
||||
AC_SUBST(DMEVENTD)
|
||||
AC_SUBST(DMEVENTD_PATH)
|
||||
AC_SUBST(DM_LIB_VERSION)
|
||||
AC_SUBST(DM_LIB_PATCHLEVEL)
|
||||
AC_SUBST(ELDFLAGS)
|
||||
AC_SUBST(FSADM)
|
||||
@@ -2023,6 +2031,7 @@ AC_SUBST(UDEV_SYNC)
|
||||
AC_SUBST(UDEV_SYSTEMD_BACKGROUND_JOBS)
|
||||
AC_SUBST(UDEV_RULE_EXEC_DETECTION)
|
||||
AC_SUBST(UDEV_HAS_BUILTIN_BLKID)
|
||||
AC_SUBST(USE_TRACKING)
|
||||
AC_SUBST(VALGRIND_POOL)
|
||||
AC_SUBST(WRITE_INSTALL)
|
||||
AC_SUBST(DMEVENTD_PIDFILE)
|
||||
@@ -2077,7 +2086,7 @@ lib/format_pool/Makefile
|
||||
lib/locking/Makefile
|
||||
lib/mirror/Makefile
|
||||
lib/replicator/Makefile
|
||||
lib/misc/lvm-version.h
|
||||
include/lvm-version.h
|
||||
lib/raid/Makefile
|
||||
lib/snapshot/Makefile
|
||||
lib/thin/Makefile
|
||||
|
||||
@@ -154,7 +154,7 @@ static void usage(const char *prog, FILE *file)
|
||||
{
|
||||
fprintf(file, "Usage: %s [options]\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"
|
||||
" -f Don't fork, run in the foreground\n"
|
||||
" -h Show this help information\n"
|
||||
|
||||
@@ -1445,7 +1445,7 @@ static int disk_status_info(struct log_c *lc, struct dm_ulog_request *rq)
|
||||
char *data = (char *)rq->data;
|
||||
struct stat statbuf;
|
||||
|
||||
if(fstat(lc->disk_fd, &statbuf)) {
|
||||
if (fstat(lc->disk_fd, &statbuf)) {
|
||||
rq->error = -errno;
|
||||
return -errno;
|
||||
}
|
||||
@@ -1508,7 +1508,7 @@ static int disk_status_table(struct log_c *lc, struct dm_ulog_request *rq)
|
||||
char *data = (char *)rq->data;
|
||||
struct stat statbuf;
|
||||
|
||||
if(fstat(lc->disk_fd, &statbuf)) {
|
||||
if (fstat(lc->disk_fd, &statbuf)) {
|
||||
rq->error = -errno;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
@@ -12,9 +12,9 @@
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "dm-logging.h"
|
||||
#include "dmlib.h"
|
||||
#include "libdevmapper-event.h"
|
||||
//#include "libmultilog.h"
|
||||
#include "dmeventd.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
@@ -23,7 +23,11 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#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;
|
||||
|
||||
struct dm_event_handler {
|
||||
@@ -194,7 +198,7 @@ static int _check_message_id(struct dm_event_daemon_message *msg)
|
||||
if ((sscanf(msg->data, "%d:%d", &pid, &seq_nr) != 2) ||
|
||||
(pid != getpid()) || (seq_nr != _sequence_nr)) {
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
@@ -229,7 +233,7 @@ static int _daemon_read(struct dm_event_fifos *fifos,
|
||||
FD_SET(fifos->server, &fds);
|
||||
ret = select(fifos->server + 1, &fds, NULL, NULL, &tval);
|
||||
if (ret < 0 && errno != EINTR) {
|
||||
log_error("Unable to read from event server");
|
||||
log_error("Unable to read from event server.");
|
||||
return 0;
|
||||
}
|
||||
if ((ret == 0) && (i > 4) && !bytes) {
|
||||
@@ -295,7 +299,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
log_error("Unable to talk to event daemon");
|
||||
log_error("Unable to talk to event daemon.");
|
||||
return 0;
|
||||
}
|
||||
if (ret == 0)
|
||||
@@ -304,7 +308,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
|
||||
if (ret < 0) {
|
||||
if ((errno == EINTR) || (errno == EAGAIN))
|
||||
continue;
|
||||
log_error("Unable to talk to event daemon");
|
||||
log_error("Unable to talk to event daemon.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -316,7 +320,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
|
||||
FD_SET(fifos->client, &fds);
|
||||
ret = select(fifos->client + 1, NULL, &fds, NULL, NULL);
|
||||
if ((ret < 0) && (errno != EINTR)) {
|
||||
log_error("Unable to talk to event daemon");
|
||||
log_error("Unable to talk to event daemon.");
|
||||
return 0;
|
||||
}
|
||||
} while (ret < 1);
|
||||
@@ -326,7 +330,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
|
||||
if ((errno == EINTR) || (errno == EAGAIN))
|
||||
continue;
|
||||
else {
|
||||
log_error("Unable to talk to event daemon");
|
||||
log_error("Unable to talk to event daemon.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -356,7 +360,7 @@ int daemon_talk(struct dm_event_fifos *fifos,
|
||||
getpid(), _sequence_nr,
|
||||
dso_name ? : "-", dev_name ? : "-", evmask, timeout)))
|
||||
< 0) {
|
||||
log_error("_daemon_talk: message allocation failed");
|
||||
log_error("_daemon_talk: message allocation failed.");
|
||||
return -ENOMEM;
|
||||
}
|
||||
msg->cmd = cmd;
|
||||
@@ -444,11 +448,11 @@ static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos)
|
||||
|
||||
else if (!pid) {
|
||||
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);
|
||||
} else {
|
||||
if (waitpid(pid, &status, 0) < 0)
|
||||
log_error("Unable to start dmeventd: %s",
|
||||
log_error("Unable to start dmeventd: %s.",
|
||||
strerror(errno));
|
||||
else if (WEXITSTATUS(status))
|
||||
log_error("Unable to start dmeventd.");
|
||||
@@ -521,7 +525,7 @@ static struct dm_task *_get_device_info(const struct dm_event_handler *dmevh)
|
||||
struct dm_info 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;
|
||||
}
|
||||
|
||||
@@ -539,17 +543,17 @@ static struct dm_task *_get_device_info(const struct dm_event_handler *dmevh)
|
||||
|
||||
/* FIXME Add name or uuid or devno to messages */
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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->dev_name) ? dmevh->dev_name : "",
|
||||
(!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? "(" : "",
|
||||
@@ -618,12 +622,12 @@ int dm_event_register_handler(const struct dm_event_handler *dmevh)
|
||||
!strstr(dmevh->dso, "libdevmapper-event-lvm2snapshot.so") &&
|
||||
!strstr(dmevh->dso, "libdevmapper-event-lvm2mirror.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,
|
||||
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),
|
||||
msg.data ? msg.data : strerror(-err));
|
||||
ret = 0;
|
||||
@@ -650,7 +654,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,
|
||||
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),
|
||||
msg.data ? msg.data : strerror(-err));
|
||||
ret = 0;
|
||||
@@ -823,6 +827,79 @@ int dm_event_get_version(struct dm_event_fifos *fifos, int *version) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dm_event_log_set(int debug_level, int use_syslog)
|
||||
{
|
||||
_debug_level = debug_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 = -1;
|
||||
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 */
|
||||
|
||||
static char *_skip_string(char *src, const int delimiter)
|
||||
@@ -856,7 +933,7 @@ int dm_event_get_timeout(const char *device_path, uint32_t *timeout)
|
||||
0, 0))) {
|
||||
char *p = _skip_string(msg.data, ' ');
|
||||
if (!p) {
|
||||
log_error("malformed reply from dmeventd '%s'\n",
|
||||
log_error("Malformed reply from dmeventd '%s'.",
|
||||
msg.data);
|
||||
dm_free(msg.data);
|
||||
return -EIO;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
@@ -105,6 +105,25 @@ 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_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_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
|
||||
detailed descriptions. */
|
||||
// FIXME misuse of bitmask as enum
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -13,15 +13,11 @@
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "log.h"
|
||||
|
||||
#include "lvm2cmd.h"
|
||||
#include "dmeventd_lvm.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "lvm2cmd.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <syslog.h>
|
||||
|
||||
extern int dmeventd_debug;
|
||||
|
||||
/*
|
||||
* register_device() is called first and performs initialisation.
|
||||
@@ -36,48 +32,19 @@ static int _register_count = 0;
|
||||
static struct dm_pool *_mem_pool = 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.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
pthread_mutex_lock(&_event_mutex);
|
||||
@@ -95,8 +62,8 @@ int dmeventd_lvm2_init(void)
|
||||
pthread_mutex_lock(&_register_mutex);
|
||||
|
||||
if (!_lvm_handle) {
|
||||
if (!getenv("LVM_LOG_FILE_EPOCH"))
|
||||
lvm2_log_fn(_temporary_log_fn);
|
||||
lvm2_log_fn(_lvm2_print_log);
|
||||
|
||||
if (!(_lvm_handle = lvm2_init()))
|
||||
goto out;
|
||||
|
||||
@@ -113,6 +80,7 @@ int dmeventd_lvm2_init(void)
|
||||
lvm2_disable_dmeventd_monitoring(_lvm_handle);
|
||||
/* FIXME Temporary: move to dmeventd core */
|
||||
lvm2_run(_lvm_handle, "_memlock_inc");
|
||||
log_debug("lvm plugin initilized.");
|
||||
}
|
||||
|
||||
_register_count++;
|
||||
@@ -128,11 +96,13 @@ void dmeventd_lvm2_exit(void)
|
||||
pthread_mutex_lock(&_register_mutex);
|
||||
|
||||
if (!--_register_count) {
|
||||
log_debug("lvm plugin shuting down.");
|
||||
lvm2_run(_lvm_handle, "_memlock_dec");
|
||||
dm_pool_destroy(_mem_pool);
|
||||
_mem_pool = NULL;
|
||||
lvm2_exit(_lvm_handle);
|
||||
_lvm_handle = NULL;
|
||||
log_debug("lvm plugin exited.");
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_register_mutex);
|
||||
@@ -155,8 +125,8 @@ int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
|
||||
int r;
|
||||
|
||||
if (!dm_split_lvm_name(mem, device, &vg, &lv, &layer)) {
|
||||
syslog(LOG_ERR, "Unable to determine VG name from %s.\n",
|
||||
device);
|
||||
log_error("Unable to determine VG name from %s.",
|
||||
device);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -170,7 +140,7 @@ int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
|
||||
dm_pool_free(mem, vg);
|
||||
|
||||
if (r < 0) {
|
||||
syslog(LOG_ERR, "Unable to form LVM command. (too long).\n");
|
||||
log_error("Unable to form LVM command. (too long).");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -39,4 +39,36 @@ struct dm_pool *dmeventd_lvm2_pool(void);
|
||||
int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
|
||||
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 */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2012 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -13,20 +13,24 @@
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
#include "libdevmapper-event.h"
|
||||
#include "dmeventd_lvm.h"
|
||||
#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. */
|
||||
|
||||
#define ME_IGNORE 0
|
||||
#define ME_INSYNC 1
|
||||
#define ME_FAILURE 2
|
||||
|
||||
struct dso_state {
|
||||
struct dm_pool *mem;
|
||||
char cmd_lvscan[512];
|
||||
char cmd_lvconvert[512];
|
||||
};
|
||||
|
||||
DM_EVENT_LOG_FN("mirr")
|
||||
|
||||
static int _process_status_code(const char status_code, const char *dev_name,
|
||||
const char *dev_type, int r)
|
||||
{
|
||||
@@ -39,18 +43,15 @@ static int _process_status_code(const char status_code, const char *dev_name,
|
||||
* U => Unclassified failure (bug)
|
||||
*/
|
||||
if (status_code == 'F') {
|
||||
syslog(LOG_ERR, "%s device %s flush failed.",
|
||||
dev_type, dev_name);
|
||||
log_error("%s device %s flush failed.", dev_type, dev_name);
|
||||
r = ME_FAILURE;
|
||||
} else if (status_code == 'S')
|
||||
syslog(LOG_ERR, "%s device %s sync failed.",
|
||||
dev_type, dev_name);
|
||||
log_error("%s device %s sync failed.", dev_type, dev_name);
|
||||
else if (status_code == 'R')
|
||||
syslog(LOG_ERR, "%s device %s read failed.",
|
||||
dev_type, dev_name);
|
||||
log_error("%s device %s read failed.", dev_type, dev_name);
|
||||
else if (status_code != 'A') {
|
||||
syslog(LOG_ERR, "%s device %s has failed (%c).",
|
||||
dev_type, dev_name, status_code);
|
||||
log_error("%s device %s has failed (%c).",
|
||||
dev_type, dev_name, status_code);
|
||||
r = ME_FAILURE;
|
||||
}
|
||||
|
||||
@@ -125,62 +126,49 @@ out:
|
||||
|
||||
out_parse:
|
||||
dm_free(args);
|
||||
syslog(LOG_ERR, "Unable to parse mirror status string.");
|
||||
log_error("Unable to parse mirror status string.");
|
||||
|
||||
return ME_IGNORE;
|
||||
}
|
||||
|
||||
static int _remove_failed_devices(const char *device)
|
||||
static int _remove_failed_devices(const char *cmd_lvscan, const char *cmd_lvconvert)
|
||||
{
|
||||
int r;
|
||||
#define CMD_SIZE 256 /* FIXME Use system restriction */
|
||||
char cmd_str[CMD_SIZE];
|
||||
|
||||
if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str),
|
||||
"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 (!dmeventd_lvm2_run_with_lock(cmd_lvscan))
|
||||
log_info("Re-scan of mirrored device failed.");
|
||||
|
||||
/* if repair goes OK, report success even if lvscan has failed */
|
||||
r = dmeventd_lvm2_run(cmd_str);
|
||||
r = dmeventd_lvm2_run_with_lock(cmd_lvconvert);
|
||||
|
||||
syslog(LOG_INFO, "Repair of mirrored device %s %s.", device,
|
||||
(r) ? "finished successfully" : "failed");
|
||||
log_info("Repair of mirrored device %s.",
|
||||
(r) ? "finished successfully" : "failed");
|
||||
|
||||
return (r) ? 0 : -1;
|
||||
return r;
|
||||
}
|
||||
|
||||
void process_event(struct dm_task *dmt,
|
||||
enum dm_event_mask event __attribute__((unused)),
|
||||
void **unused __attribute__((unused)))
|
||||
void **user)
|
||||
{
|
||||
struct dso_state *state = *user;
|
||||
void *next = NULL;
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
char *params;
|
||||
const char *device = dm_task_get_name(dmt);
|
||||
|
||||
dmeventd_lvm2_lock();
|
||||
|
||||
do {
|
||||
next = dm_get_next_target(dmt, next, &start, &length,
|
||||
&target_type, ¶ms);
|
||||
|
||||
if (!target_type) {
|
||||
syslog(LOG_INFO, "%s mapping lost.", device);
|
||||
log_info("%s mapping lost.", device);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(target_type, "mirror")) {
|
||||
syslog(LOG_INFO, "%s has unmirrored portion.", device);
|
||||
log_info("%s has unmirrored portion.", device);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -190,54 +178,75 @@ void process_event(struct dm_task *dmt,
|
||||
_part_ of the device is in sync
|
||||
Also, this is not an error
|
||||
*/
|
||||
syslog(LOG_NOTICE, "%s is now in-sync.", device);
|
||||
log_notice("%s is now in-sync.", device);
|
||||
break;
|
||||
case ME_FAILURE:
|
||||
syslog(LOG_ERR, "Device failure in %s.", device);
|
||||
if (_remove_failed_devices(device))
|
||||
log_error("Device failure in %s.", device);
|
||||
if (!_remove_failed_devices(state->cmd_lvscan,
|
||||
state->cmd_lvconvert))
|
||||
/* FIXME Why are all the error return codes unused? Get rid of them? */
|
||||
syslog(LOG_ERR, "Failed to remove faulty devices in %s.",
|
||||
device);
|
||||
log_error("Failed to remove faulty devices in %s.",
|
||||
device);
|
||||
/* Should check before warning user that device is now linear
|
||||
else
|
||||
syslog(LOG_NOTICE, "%s is now a linear device.\n",
|
||||
device);
|
||||
log_notice("%s is now a linear device.",
|
||||
device);
|
||||
*/
|
||||
break;
|
||||
case ME_IGNORE:
|
||||
break;
|
||||
default:
|
||||
/* FIXME Provide value then! */
|
||||
syslog(LOG_INFO, "Unknown event received.");
|
||||
log_info("Unknown event received.");
|
||||
}
|
||||
} while (next);
|
||||
|
||||
dmeventd_lvm2_unlock();
|
||||
}
|
||||
|
||||
int register_device(const char *device,
|
||||
const char *uuid __attribute__((unused)),
|
||||
int major __attribute__((unused)),
|
||||
int minor __attribute__((unused)),
|
||||
void **unused __attribute__((unused)))
|
||||
void **user)
|
||||
{
|
||||
if (!dmeventd_lvm2_init())
|
||||
return 0;
|
||||
struct dso_state *state;
|
||||
|
||||
syslog(LOG_INFO, "Monitoring mirror device %s for events.", device);
|
||||
if (!dmeventd_lvm2_init_with_pool("mirror_state", state))
|
||||
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;
|
||||
bad:
|
||||
log_error("Failed to monitor mirror %s.", device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unregister_device(const char *device,
|
||||
const char *uuid __attribute__((unused)),
|
||||
int major __attribute__((unused)),
|
||||
int minor __attribute__((unused)),
|
||||
void **unused __attribute__((unused)))
|
||||
void **user)
|
||||
{
|
||||
syslog(LOG_INFO, "No longer monitoring mirror device %s for events.",
|
||||
device);
|
||||
dmeventd_lvm2_exit();
|
||||
struct dso_state *state = *user;
|
||||
|
||||
dmeventd_lvm2_exit_with_pool(state);
|
||||
log_info("No longer monitoring mirror device %s for events.",
|
||||
device);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2011 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -13,168 +13,133 @@
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
#include "libdevmapper-event.h"
|
||||
#include "dmeventd_lvm.h"
|
||||
#include "libdevmapper-event.h"
|
||||
|
||||
struct dso_state {
|
||||
struct dm_pool *mem;
|
||||
char cmd_lvscan[512];
|
||||
char cmd_lvconvert[512];
|
||||
int failed;
|
||||
};
|
||||
|
||||
DM_EVENT_LOG_FN("raid")
|
||||
|
||||
#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. */
|
||||
|
||||
/*
|
||||
* run_repair is a close copy to
|
||||
* plugins/mirror/dmeventd_mirror.c:_remove_failed_devices()
|
||||
*/
|
||||
static int run_repair(const char *device)
|
||||
static int _process_raid_event(struct dso_state *state, char *params, const char *device)
|
||||
{
|
||||
int r;
|
||||
#define CMD_SIZE 256 /* FIXME Use system restriction */
|
||||
char cmd_str[CMD_SIZE];
|
||||
struct dm_status_raid *status;
|
||||
const char *d;
|
||||
|
||||
if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str),
|
||||
"lvscan --cache", device))
|
||||
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 (!dm_get_status_raid(state->mem, params, &status)) {
|
||||
log_error("Failed to process status line for %s.", device);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
switch (health_chars[i]) {
|
||||
case 'A':
|
||||
/* Device is 'A'live and well */
|
||||
case 'a':
|
||||
/* Device is 'a'live, but not yet in-sync */
|
||||
break;
|
||||
case 'D':
|
||||
syslog(LOG_ERR,
|
||||
"Device #%d of %s array, %s, has failed.",
|
||||
i, raid_type, device);
|
||||
failure++;
|
||||
break;
|
||||
default:
|
||||
/* Unhandled character returned from kernel */
|
||||
break;
|
||||
if ((d = strchr(status->dev_health, 'D'))) {
|
||||
if (state->failed)
|
||||
goto out; /* already reported */
|
||||
|
||||
log_error("Device #%d of %s array, %s, has failed.",
|
||||
(int)(d - status->dev_health),
|
||||
status->raid_type, device);
|
||||
|
||||
state->failed = 1;
|
||||
if (!dmeventd_lvm2_run_with_lock(state->cmd_lvscan))
|
||||
log_warn("WARNING: Re-scan of RAID device %s failed.", device);
|
||||
|
||||
/* if repair goes OK, report success even if lvscan has failed */
|
||||
if (!dmeventd_lvm2_run_with_lock(state->cmd_lvconvert)) {
|
||||
log_info("Repair of RAID device %s failed.", device);
|
||||
dm_pool_free(state->mem, status);
|
||||
return 0;
|
||||
}
|
||||
if (failure)
|
||||
return run_repair(device);
|
||||
} else {
|
||||
state->failed = 0;
|
||||
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);
|
||||
|
||||
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;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void process_event(struct dm_task *dmt,
|
||||
enum dm_event_mask event __attribute__((unused)),
|
||||
void **unused __attribute__((unused)))
|
||||
void **user)
|
||||
{
|
||||
struct dso_state *state = *user;
|
||||
void *next = NULL;
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
char *params;
|
||||
const char *device = dm_task_get_name(dmt);
|
||||
|
||||
dmeventd_lvm2_lock();
|
||||
|
||||
do {
|
||||
next = dm_get_next_target(dmt, next, &start, &length,
|
||||
&target_type, ¶ms);
|
||||
|
||||
if (!target_type) {
|
||||
syslog(LOG_INFO, "%s mapping lost.", device);
|
||||
log_info("%s mapping lost.", device);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(target_type, "raid")) {
|
||||
syslog(LOG_INFO, "%s has non-raid portion.", device);
|
||||
log_info("%s has non-raid portion.", device);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_process_raid_event(params, device))
|
||||
syslog(LOG_ERR, "Failed to process event for %s",
|
||||
device);
|
||||
if (!_process_raid_event(state, params, device))
|
||||
log_error("Failed to process event for %s.",
|
||||
device);
|
||||
} while (next);
|
||||
|
||||
dmeventd_lvm2_unlock();
|
||||
}
|
||||
|
||||
int register_device(const char *device,
|
||||
const char *uuid __attribute__((unused)),
|
||||
int major __attribute__((unused)),
|
||||
int minor __attribute__((unused)),
|
||||
void **unused __attribute__((unused)))
|
||||
void **user)
|
||||
{
|
||||
if (!dmeventd_lvm2_init())
|
||||
return 0;
|
||||
struct dso_state *state;
|
||||
|
||||
syslog(LOG_INFO, "Monitoring RAID device %s for events.", device);
|
||||
if (!dmeventd_lvm2_init_with_pool("raid_state", state))
|
||||
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;
|
||||
bad:
|
||||
log_error("Failed to monitor RAID %s.", device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unregister_device(const char *device,
|
||||
const char *uuid __attribute__((unused)),
|
||||
int major __attribute__((unused)),
|
||||
int minor __attribute__((unused)),
|
||||
void **unused __attribute__((unused)))
|
||||
void **user)
|
||||
{
|
||||
syslog(LOG_INFO, "No longer monitoring RAID device %s for events.",
|
||||
device);
|
||||
dmeventd_lvm2_exit();
|
||||
struct dso_state *state = *user;
|
||||
|
||||
dmeventd_lvm2_exit_with_pool(state);
|
||||
log_info("No longer monitoring RAID device %s for events.",
|
||||
device);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2011 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2007-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -13,31 +13,31 @@
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
#include "libdevmapper-event.h"
|
||||
#include "dmeventd_lvm.h"
|
||||
#include "libdevmapper-event.h"
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <syslog.h> /* FIXME Replace syslog with multilog */
|
||||
#include <stdarg.h>
|
||||
/* FIXME Missing openlog? */
|
||||
#include <pthread.h>
|
||||
|
||||
/* First warning when snapshot is 80% full. */
|
||||
#define WARNING_THRESH 80
|
||||
#define WARNING_THRESH (DM_PERCENT_1 * 80)
|
||||
/* Run a check every 5%. */
|
||||
#define CHECK_STEP 5
|
||||
#define CHECK_STEP (DM_PERCENT_1 * 5)
|
||||
/* Do not bother checking snapshots less than 50% full. */
|
||||
#define CHECK_MINIMUM 50
|
||||
#define CHECK_MINIMUM (DM_PERCENT_1 * 50)
|
||||
|
||||
#define UMOUNT_COMMAND "/bin/umount"
|
||||
|
||||
struct dso_state {
|
||||
struct dm_pool *mem;
|
||||
int percent_check;
|
||||
dm_percent_t percent_check;
|
||||
uint64_t known_size;
|
||||
char cmd_str[1024];
|
||||
char cmd_lvextend[512];
|
||||
};
|
||||
|
||||
DM_EVENT_LOG_FN("snap")
|
||||
|
||||
static int _run(const char *cmd, ...)
|
||||
{
|
||||
va_list ap;
|
||||
@@ -62,7 +62,7 @@ static int _run(const char *cmd, ...)
|
||||
va_end(ap);
|
||||
|
||||
execvp(cmd, (char **)argv);
|
||||
syslog(LOG_ERR, "Failed to execute %s: %s.\n", cmd, strerror(errno));
|
||||
log_sys_error("exec", cmd);
|
||||
exit(127);
|
||||
}
|
||||
|
||||
@@ -81,18 +81,56 @@ static int _run(const char *cmd, ...)
|
||||
|
||||
static int _extend(const char *cmd)
|
||||
{
|
||||
return dmeventd_lvm2_run(cmd);
|
||||
log_debug("Extending snapshot via %s.", 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)
|
||||
{
|
||||
FILE *mounts;
|
||||
char buffer[4096];
|
||||
char *words[3];
|
||||
struct stat st;
|
||||
const char procmounts[] = "/proc/mounts";
|
||||
|
||||
if (!(mounts = fopen("/proc/mounts", "r"))) {
|
||||
syslog(LOG_ERR, "Could not read /proc/mounts. Not umounting %s.\n", device);
|
||||
if (!(mounts = fopen(procmounts, "r"))) {
|
||||
log_sys_error("fopen", procmounts);
|
||||
log_error("Not umounting %s.", device);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -112,21 +150,22 @@ static void _umount(const char *device, int major, int minor)
|
||||
if (S_ISBLK(st.st_mode) &&
|
||||
major(st.st_rdev) == major &&
|
||||
minor(st.st_rdev) == minor) {
|
||||
syslog(LOG_ERR, "Unmounting invalid snapshot %s from %s.\n", device, words[1]);
|
||||
if (!_run(UMOUNT_COMMAND, "-fl", words[1], NULL))
|
||||
syslog(LOG_ERR, "Failed to umount snapshot %s from %s: %s.\n",
|
||||
device, words[1], strerror(errno));
|
||||
log_error("Unmounting invalid snapshot %s from %s.", device, words[1]);
|
||||
if (!_run(UMOUNT_COMMAND, "-fl", words[1], NULL))
|
||||
log_error("Failed to umount snapshot %s from %s: %s.",
|
||||
device, words[1], strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
if (fclose(mounts))
|
||||
syslog(LOG_ERR, "Failed to close /proc/mounts.\n");
|
||||
log_sys_error("close", procmounts);
|
||||
}
|
||||
|
||||
void process_event(struct dm_task *dmt,
|
||||
enum dm_event_mask event __attribute__((unused)),
|
||||
void **private)
|
||||
void **user)
|
||||
{
|
||||
struct dso_state *state = *user;
|
||||
void *next = NULL;
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
@@ -134,28 +173,47 @@ void process_event(struct dm_task *dmt,
|
||||
struct dm_status_snapshot *status = NULL;
|
||||
const char *device = dm_task_get_name(dmt);
|
||||
int percent;
|
||||
struct dso_state *state = *private;
|
||||
struct dm_info info;
|
||||
|
||||
/* No longer monitoring, waiting for remove */
|
||||
if (!state->percent_check)
|
||||
return;
|
||||
|
||||
dmeventd_lvm2_lock();
|
||||
|
||||
dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
||||
if (!target_type)
|
||||
goto out;
|
||||
if (!target_type || strcmp(target_type, "snapshot")) {
|
||||
log_error("Target %s is not snapshot.", target_type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dm_get_status_snapshot(state->mem, params, &status))
|
||||
goto out;
|
||||
if (!dm_get_status_snapshot(state->mem, params, &status)) {
|
||||
log_error("Cannot parse snapshot %s state: %s.", device, params);
|
||||
return;
|
||||
}
|
||||
|
||||
if (status->invalid) {
|
||||
struct dm_info info;
|
||||
if (dm_task_get_info(dmt, &info)) {
|
||||
dmeventd_lvm2_unlock();
|
||||
/*
|
||||
* 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->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);
|
||||
return;
|
||||
} /* else; too bad, but this is best-effort thing... */
|
||||
#ifdef SNAPSHOT_REMOVE
|
||||
/* Maybe configurable ? */
|
||||
_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. */
|
||||
@@ -164,69 +222,50 @@ void process_event(struct dm_task *dmt,
|
||||
state->known_size = 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);
|
||||
percent = dm_make_percent(status->used_sectors, status->total_sectors);
|
||||
if (percent >= state->percent_check) {
|
||||
/* Usage has raised more than CHECK_STEP since the last
|
||||
time. Run actions. */
|
||||
state->percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
|
||||
|
||||
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
|
||||
syslog(LOG_WARNING, "Snapshot %s is now %i%% full.\n", device, percent);
|
||||
/* Try to extend the snapshot, in accord with user-set policies */
|
||||
if (!_extend(state->cmd_str))
|
||||
syslog(LOG_ERR, "Failed to extend snapshot %s.\n", device);
|
||||
}
|
||||
log_warn("WARNING: Snapshot %s is now %.2f%% full.",
|
||||
device, dm_percent_to_float(percent));
|
||||
|
||||
/* Try to extend the snapshot, in accord with user-set policies */
|
||||
if (!_extend(state->cmd_lvextend))
|
||||
log_error("Failed to extend snapshot %s.", device);
|
||||
}
|
||||
out:
|
||||
if (status)
|
||||
dm_pool_free(state->mem, status);
|
||||
dmeventd_lvm2_unlock();
|
||||
dm_pool_free(state->mem, status);
|
||||
}
|
||||
|
||||
int register_device(const char *device,
|
||||
const char *uuid __attribute__((unused)),
|
||||
int major __attribute__((unused)),
|
||||
int minor __attribute__((unused)),
|
||||
void **private)
|
||||
void **user)
|
||||
{
|
||||
struct dm_pool *statemem = NULL;
|
||||
struct dso_state *state;
|
||||
|
||||
if (!dmeventd_lvm2_init())
|
||||
goto out;
|
||||
if (!dmeventd_lvm2_init_with_pool("snapshot_state", state))
|
||||
goto_bad;
|
||||
|
||||
if (!(statemem = dm_pool_create("snapshot_state", 512)) ||
|
||||
!(state = dm_pool_zalloc(statemem, sizeof(*state))))
|
||||
goto bad;
|
||||
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvextend,
|
||||
sizeof(state->cmd_lvextend),
|
||||
"lvextend --use-policies", device)) {
|
||||
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;
|
||||
*private = state;
|
||||
*user = state;
|
||||
|
||||
syslog(LOG_INFO, "Monitoring snapshot %s\n", device);
|
||||
log_info("Monitoring snapshot %s.", device);
|
||||
|
||||
return 1;
|
||||
bad:
|
||||
if (statemem)
|
||||
dm_pool_destroy(statemem);
|
||||
dmeventd_lvm2_exit();
|
||||
out:
|
||||
syslog(LOG_ERR, "Failed to monitor snapshot %s.\n", device);
|
||||
log_error("Failed to monitor snapshot %s.", device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -235,13 +274,12 @@ int unregister_device(const char *device,
|
||||
const char *uuid __attribute__((unused)),
|
||||
int major __attribute__((unused)),
|
||||
int minor __attribute__((unused)),
|
||||
void **private)
|
||||
void **user)
|
||||
{
|
||||
struct dso_state *state = *private;
|
||||
struct dso_state *state = *user;
|
||||
|
||||
syslog(LOG_INFO, "No longer monitoring snapshot %s\n", device);
|
||||
dm_pool_destroy(state->mem);
|
||||
dmeventd_lvm2_exit();
|
||||
dmeventd_lvm2_exit_with_pool(state);
|
||||
log_info("No longer monitoring snapshot %s.", device);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2011-2013 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -12,25 +12,33 @@
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
#include "libdevmapper-event.h"
|
||||
#include "lib.h" /* using here lvm log */
|
||||
#include "dmeventd_lvm.h"
|
||||
#include "libdevmapper-event.h"
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <syslog.h> /* FIXME Replace syslog with multilog */
|
||||
#include <stdarg.h>
|
||||
/* FIXME Missing openlog? */
|
||||
#include <pthread.h>
|
||||
|
||||
/* First warning when thin is 80% full. */
|
||||
#define WARNING_THRESH 80
|
||||
/* TODO - move this mountinfo code into library to be reusable */
|
||||
#ifdef __linux__
|
||||
# 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)
|
||||
/* Run a check every 5%. */
|
||||
#define CHECK_STEP 5
|
||||
/* Do not bother checking thins less than 50% full. */
|
||||
#define CHECK_MINIMUM 50
|
||||
#define CHECK_STEP (DM_PERCENT_1 * 5)
|
||||
/* Do not bother checking thin data or metadata is less than 50% full. */
|
||||
#define CHECK_MINIMUM (DM_PERCENT_1 * 50)
|
||||
|
||||
#define UMOUNT_COMMAND "/bin/umount"
|
||||
|
||||
#define MAX_FAILS (10)
|
||||
|
||||
#define THIN_DEBUG 0
|
||||
|
||||
struct dso_state {
|
||||
@@ -39,18 +47,11 @@ struct dso_state {
|
||||
int data_percent_check;
|
||||
uint64_t known_metadata_size;
|
||||
uint64_t known_data_size;
|
||||
unsigned fails;
|
||||
char cmd_str[1024];
|
||||
};
|
||||
|
||||
|
||||
/* TODO - move this mountinfo code into library to be reusable */
|
||||
#ifdef __linux__
|
||||
# include "kdev_t.h"
|
||||
#else
|
||||
# define MAJOR(x) major((x))
|
||||
# define MINOR(x) minor((x))
|
||||
# define MKDEV(x,y) makedev((x),(y))
|
||||
#endif
|
||||
DM_EVENT_LOG_FN("thin")
|
||||
|
||||
/* 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)
|
||||
@@ -93,8 +94,8 @@ static int _has_deps(const char *name, int tp_major, int tp_minor, int *dev_mino
|
||||
{
|
||||
char dev_name[PATH_MAX];
|
||||
if (dm_device_get_name(major, minor, 0, dev_name, sizeof(dev_name)))
|
||||
syslog(LOG_DEBUG, "Found %s (%u:%u) depends on %s",
|
||||
name, major, *dev_minor, dev_name);
|
||||
log_debug("Found %s (%u:%u) depends on %s.",
|
||||
name, major, *dev_minor, dev_name);
|
||||
}
|
||||
#endif
|
||||
r = 1;
|
||||
@@ -141,14 +142,6 @@ out:
|
||||
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, ...)
|
||||
{
|
||||
va_list ap;
|
||||
@@ -168,12 +161,12 @@ static int _run(const char *cmd, ...)
|
||||
argv = alloca(sizeof(const char *) * (argc + 1));
|
||||
|
||||
argv[0] = cmd;
|
||||
va_start(ap, cmd);
|
||||
va_start(ap, cmd);
|
||||
while ((argv[++i] = va_arg(ap, const char *)));
|
||||
va_end(ap);
|
||||
|
||||
execvp(cmd, (char **)argv);
|
||||
syslog(LOG_ERR, "Failed to execute %s: %s.\n", cmd, strerror(errno));
|
||||
log_sys_error("exec", cmd);
|
||||
exit(127);
|
||||
}
|
||||
|
||||
@@ -191,9 +184,9 @@ static int _run(const char *cmd, ...)
|
||||
}
|
||||
|
||||
struct mountinfo_s {
|
||||
const char *device;
|
||||
struct dm_info info;
|
||||
dm_bitset_t minors; /* Bitset for active thin pool minors */
|
||||
const char *device;
|
||||
};
|
||||
|
||||
static int _umount_device(char *buffer, unsigned major, unsigned minor,
|
||||
@@ -202,11 +195,11 @@ static int _umount_device(char *buffer, unsigned major, unsigned minor,
|
||||
struct mountinfo_s *data = cb_data;
|
||||
|
||||
if ((major == data->info.major) && dm_bit(data->minors, minor)) {
|
||||
syslog(LOG_INFO, "Unmounting thin volume %s from %s.\n",
|
||||
data->device, target);
|
||||
log_info("Unmounting thin volume %s from %s.",
|
||||
data->device, target);
|
||||
if (!_run(UMOUNT_COMMAND, "-fl", target, NULL))
|
||||
syslog(LOG_ERR, "Failed to umount thin %s from %s: %s.\n",
|
||||
data->device, target, strerror(errno));
|
||||
log_error("Failed to umount thin %s from %s: %s.",
|
||||
data->device, target, strerror(errno));
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -216,78 +209,94 @@ static int _umount_device(char *buffer, unsigned major, unsigned minor,
|
||||
* Find all thin pool users and try to umount them.
|
||||
* TODO: work with read-only thin pool support
|
||||
*/
|
||||
static void _umount(struct dm_task *dmt, const char *device)
|
||||
static void _umount(struct dm_task *dmt)
|
||||
{
|
||||
/* TODO: Convert to use hash to reduce memory usage */
|
||||
static const size_t MINORS = (1U << 20); /* 20 bit */
|
||||
struct mountinfo_s data = {
|
||||
.device = device,
|
||||
};
|
||||
struct mountinfo_s data = { NULL };
|
||||
|
||||
if (!dm_task_get_info(dmt, &data.info))
|
||||
return;
|
||||
|
||||
dmeventd_lvm2_unlock();
|
||||
data.device = dm_task_get_name(dmt);
|
||||
|
||||
if (!(data.minors = dm_bitset_create(NULL, MINORS))) {
|
||||
syslog(LOG_ERR, "Failed to allocate bitset. Not unmounting %s.\n", device);
|
||||
log_error("Failed to allocate bitset. Not unmounting %s.", data.device);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!_find_all_devs(data.minors, data.info.major, data.info.minor)) {
|
||||
syslog(LOG_ERR, "Failed to detect mounted volumes for %s.\n", device);
|
||||
log_error("Failed to detect mounted volumes for %s.", data.device);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!dm_mountinfo_read(_umount_device, &data)) {
|
||||
syslog(LOG_ERR, "Could not parse mountinfo file.\n");
|
||||
log_error("Could not parse mountinfo file.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
if (data.minors)
|
||||
dm_bitset_destroy(data.minors);
|
||||
dmeventd_lvm2_lock();
|
||||
}
|
||||
|
||||
static void _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));
|
||||
_umount(dmt);
|
||||
state->fails++;
|
||||
} else
|
||||
state->fails = 0;
|
||||
}
|
||||
|
||||
void process_event(struct dm_task *dmt,
|
||||
enum dm_event_mask event __attribute__((unused)),
|
||||
void **private)
|
||||
void **user)
|
||||
{
|
||||
const char *device = dm_task_get_name(dmt);
|
||||
int percent;
|
||||
struct dso_state *state = *private;
|
||||
struct dso_state *state = *user;
|
||||
struct dm_status_thin_pool *tps = NULL;
|
||||
void *next = NULL;
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
char *params;
|
||||
int needs_policy = 0;
|
||||
|
||||
#if 0
|
||||
/* No longer monitoring, waiting for remove */
|
||||
if (!state->meta_percent_check && !state->data_percent_check)
|
||||
return;
|
||||
#endif
|
||||
dmeventd_lvm2_lock();
|
||||
if (event & DM_EVENT_DEVICE_ERROR) {
|
||||
/* Error -> no need to check and do instant resize */
|
||||
_use_policy(dmt, state);
|
||||
goto out;
|
||||
}
|
||||
|
||||
dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
||||
|
||||
if (!target_type || (strcmp(target_type, "thin-pool") != 0)) {
|
||||
syslog(LOG_ERR, "Invalid target type.\n");
|
||||
log_error("Invalid target type.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!dm_get_status_thin_pool(state->mem, params, &tps)) {
|
||||
syslog(LOG_ERR, "Failed to parse status.\n");
|
||||
_umount(dmt, device);
|
||||
log_error("Failed to parse status.");
|
||||
_umount(dmt);
|
||||
goto out;
|
||||
}
|
||||
|
||||
#if THIN_DEBUG
|
||||
syslog(LOG_INFO, "%p: Got status %" PRIu64 " / %" PRIu64
|
||||
" %" PRIu64 " / %" PRIu64 ".\n", state,
|
||||
tps->used_metadata_blocks, tps->total_metadata_blocks,
|
||||
tps->used_data_blocks, tps->total_data_blocks);
|
||||
log_debug("Thin pool status " FMTu64 "/" FMTu64 " "
|
||||
FMTu64 "/" FMTu64 ".",
|
||||
tps->used_metadata_blocks, tps->total_metadata_blocks,
|
||||
tps->used_data_blocks, tps->total_data_blocks);
|
||||
#endif
|
||||
|
||||
/* Thin pool size had changed. Clear the threshold. */
|
||||
@@ -301,7 +310,7 @@ void process_event(struct dm_task *dmt,
|
||||
state->known_data_size = tps->total_data_blocks;
|
||||
}
|
||||
|
||||
percent = 100 * tps->used_metadata_blocks / tps->total_metadata_blocks;
|
||||
percent = dm_make_percent(tps->used_metadata_blocks, tps->total_metadata_blocks);
|
||||
if (percent >= state->metadata_percent_check) {
|
||||
/*
|
||||
* Usage has raised more than CHECK_STEP since the last
|
||||
@@ -311,18 +320,12 @@ void process_event(struct dm_task *dmt,
|
||||
|
||||
/* FIXME: extension of metadata needs to be written! */
|
||||
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
|
||||
syslog(LOG_WARNING, "Thin metadata %s is now %i%% full.\n",
|
||||
device, percent);
|
||||
/* Try to extend the metadata, in accord with user-set policies */
|
||||
if (!_extend(state)) {
|
||||
syslog(LOG_ERR, "Failed to extend thin metadata %s.\n",
|
||||
device);
|
||||
_umount(dmt, device);
|
||||
}
|
||||
/* FIXME: hmm READ-ONLY switch should happen in error path */
|
||||
log_warn("WARNING: Thin pool %s metadata is now %.2f%% full.",
|
||||
device, dm_percent_to_float(percent));
|
||||
needs_policy = 1;
|
||||
}
|
||||
|
||||
percent = 100 * tps->used_data_blocks / tps->total_data_blocks;
|
||||
percent = dm_make_percent(tps->used_data_blocks, tps->total_data_blocks);
|
||||
if (percent >= state->data_percent_check) {
|
||||
/*
|
||||
* Usage has raised more than CHECK_STEP since
|
||||
@@ -331,56 +334,53 @@ void process_event(struct dm_task *dmt,
|
||||
state->data_percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
|
||||
|
||||
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
|
||||
syslog(LOG_WARNING, "Thin %s is now %i%% full.\n", device, percent);
|
||||
/* Try to extend the thin data, in accord with user-set policies */
|
||||
if (!_extend(state)) {
|
||||
syslog(LOG_ERR, "Failed to extend thin %s.\n", device);
|
||||
state->data_percent_check = 0;
|
||||
_umount(dmt, device);
|
||||
}
|
||||
/* FIXME: hmm READ-ONLY switch should happen in error path */
|
||||
log_warn("WARNING: Thin pool %s data is now %.2f%% full.",
|
||||
device, dm_percent_to_float(percent));
|
||||
needs_policy = 1;
|
||||
}
|
||||
|
||||
if (needs_policy)
|
||||
_use_policy(dmt, state);
|
||||
out:
|
||||
if (tps)
|
||||
dm_pool_free(state->mem, tps);
|
||||
|
||||
dmeventd_lvm2_unlock();
|
||||
if (state->fails >= MAX_FAILS) {
|
||||
log_warn("WARNING: Dropping monitoring of %s. "
|
||||
"lvm2 command fails too often (%u times in raw).",
|
||||
device, state->fails);
|
||||
pthread_kill(pthread_self(), SIGALRM);
|
||||
}
|
||||
}
|
||||
|
||||
int register_device(const char *device,
|
||||
const char *uuid __attribute__((unused)),
|
||||
int major __attribute__((unused)),
|
||||
int minor __attribute__((unused)),
|
||||
void **private)
|
||||
void **user)
|
||||
{
|
||||
struct dm_pool *statemem = NULL;
|
||||
struct dso_state *state;
|
||||
|
||||
if (!dmeventd_lvm2_init())
|
||||
goto bad;
|
||||
if (!dmeventd_lvm2_init_with_pool("thin_pool_state", state))
|
||||
goto_bad;
|
||||
|
||||
if (!(statemem = dm_pool_create("thin_pool_state", 2048)) ||
|
||||
!(state = dm_pool_zalloc(statemem, sizeof(*state))) ||
|
||||
!dmeventd_lvm2_command(statemem, state->cmd_str,
|
||||
if (!dmeventd_lvm2_command(state->mem, state->cmd_str,
|
||||
sizeof(state->cmd_str),
|
||||
"lvextend --use-policies",
|
||||
device)) {
|
||||
if (statemem)
|
||||
dm_pool_destroy(statemem);
|
||||
dmeventd_lvm2_exit();
|
||||
goto bad;
|
||||
dmeventd_lvm2_exit_with_pool(state);
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
state->mem = statemem;
|
||||
state->metadata_percent_check = CHECK_MINIMUM;
|
||||
state->data_percent_check = CHECK_MINIMUM;
|
||||
*private = state;
|
||||
*user = state;
|
||||
|
||||
syslog(LOG_INFO, "Monitoring thin %s.\n", device);
|
||||
log_info("Monitoring thin %s.", device);
|
||||
|
||||
return 1;
|
||||
bad:
|
||||
syslog(LOG_ERR, "Failed to monitor thin %s.\n", device);
|
||||
log_error("Failed to monitor thin %s.", device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -389,13 +389,12 @@ int unregister_device(const char *device,
|
||||
const char *uuid __attribute__((unused)),
|
||||
int major __attribute__((unused)),
|
||||
int minor __attribute__((unused)),
|
||||
void **private)
|
||||
void **user)
|
||||
{
|
||||
struct dso_state *state = *private;
|
||||
struct dso_state *state = *user;
|
||||
|
||||
syslog(LOG_INFO, "No longer monitoring thin %s.\n", device);
|
||||
dm_pool_destroy(state->mem);
|
||||
dmeventd_lvm2_exit();
|
||||
dmeventd_lvm2_exit_with_pool(state);
|
||||
log_info("No longer monitoring thin %s.", device);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -45,6 +45,8 @@ lvmetactl: lvmetactl.o $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmetactl.o $(LVMLIBS)
|
||||
|
||||
CLEAN_TARGETS += lvmetactl.o
|
||||
|
||||
# TODO: No idea. No idea how to test either.
|
||||
#ifneq ("$(CFLOW_CMD)", "")
|
||||
#CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Red Hat, Inc.
|
||||
* Copyright (C) 2012-2015 Red Hat, Inc.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "lvm-version.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#define LVMETAD_SOCKET DEFAULT_RUN_DIR "/lvmetad.socket"
|
||||
@@ -123,6 +124,7 @@ struct vg_info {
|
||||
#define VGFL_INVALID 0x00000001
|
||||
|
||||
typedef struct {
|
||||
daemon_idle *idle;
|
||||
log_state *log; /* convenience */
|
||||
const char *log_config;
|
||||
|
||||
@@ -578,7 +580,7 @@ static void mark_outdated_pv(lvmetad_state *s, const char *vgid, const char *pvi
|
||||
!(cft_vgid = make_text_node(outdated_pvs, "vgid", dm_pool_strdup(outdated_pvs->mem, vgid),
|
||||
outdated_pvs->root, NULL)))
|
||||
abort();
|
||||
if(!dm_hash_insert(s->vgid_to_outdated_pvs, cft_vgid->v->v.str, outdated_pvs))
|
||||
if (!dm_hash_insert(s->vgid_to_outdated_pvs, cft_vgid->v->v.str, outdated_pvs))
|
||||
abort();
|
||||
DEBUGLOG(s, "created outdated_pvs list for VG %s", vgid);
|
||||
}
|
||||
@@ -1592,6 +1594,9 @@ static int init(daemon_state *s)
|
||||
/* if (ls->initial_registrations)
|
||||
_process_initial_registrations(ds->initial_registrations); */
|
||||
|
||||
if (ls->idle)
|
||||
ls->idle->is_idle = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1614,21 +1619,39 @@ static int fini(daemon_state *s)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int process_timeout_arg(const char *str, unsigned *max_timeouts)
|
||||
{
|
||||
char *endptr;
|
||||
unsigned long l;
|
||||
|
||||
errno = 0;
|
||||
l = strtoul(str, &endptr, 10);
|
||||
if (errno || *endptr || l >= UINT_MAX)
|
||||
return 0;
|
||||
|
||||
*max_timeouts = (unsigned) l;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void usage(const char *prog, FILE *file)
|
||||
{
|
||||
fprintf(file, "Usage:\n"
|
||||
"%s [-V] [-h] [-f] [-l {all|wire|debug}] [-s path]\n\n"
|
||||
"%s [-V] [-h] [-f] [-l level[,level ...]] [-s path] [-t secs]\n\n"
|
||||
" -V Show version of lvmetad\n"
|
||||
" -h Show this help information\n"
|
||||
" -f Don't fork, run in the foreground\n"
|
||||
" -l Logging message level (-l {all|wire|debug})\n"
|
||||
" -l Logging message levels (all,fatal,error,warn,info,wire,debug)\n"
|
||||
" -p Set path to the pidfile\n"
|
||||
" -s Set path to the socket to listen on\n\n", prog);
|
||||
" -s Set path to the socket to listen on\n"
|
||||
" -t Time to wait in seconds before shutdown on idle (missing or 0 = inifinite)\n\n", prog);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
signed char opt;
|
||||
struct timeval timeout;
|
||||
daemon_idle di = { .ptimeout = &timeout };
|
||||
lvmetad_state ls = { .log_config = "" };
|
||||
daemon_state s = {
|
||||
.daemon_fini = fini,
|
||||
@@ -1643,7 +1666,7 @@ int main(int argc, char *argv[])
|
||||
};
|
||||
|
||||
// use getopt_long
|
||||
while ((opt = getopt(argc, argv, "?fhVl:p:s:")) != EOF) {
|
||||
while ((opt = getopt(argc, argv, "?fhVl:p:s:t:")) != EOF) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
usage(argv[0], stdout);
|
||||
@@ -1663,6 +1686,15 @@ int main(int argc, char *argv[])
|
||||
case 's': // --socket
|
||||
s.socket_path = optarg;
|
||||
break;
|
||||
case 't':
|
||||
if (!process_timeout_arg(optarg, &di.max_timeouts)) {
|
||||
fprintf(stderr, "Invalid value of timeout parameter.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* 0 equals to wait indefinitely */
|
||||
if (di.max_timeouts)
|
||||
s.idle = ls.idle = &di;
|
||||
break;
|
||||
case 'V':
|
||||
printf("lvmetad version: " LVM_VERSION "\n");
|
||||
exit(1);
|
||||
|
||||
@@ -197,11 +197,11 @@ static pthread_mutex_t client_mutex;
|
||||
static pthread_cond_t client_cond;
|
||||
static struct list_head client_list; /* connected clients */
|
||||
static struct list_head client_results; /* actions to send back to clients */
|
||||
static uint32_t client_ids; /* 0 and ADOPT_CLIENT_ID are skipped */
|
||||
static uint32_t client_ids; /* 0 and INTERNAL_CLIENT_ID are skipped */
|
||||
static int client_stop; /* stop the thread */
|
||||
static int client_work; /* a client on client_list has work to do */
|
||||
|
||||
#define ADOPT_CLIENT_ID 0xFFFFFFFF /* special client_id for adopt actions */
|
||||
#define INTERNAL_CLIENT_ID 0xFFFFFFFF /* special client_id for internal actions */
|
||||
static struct list_head adopt_results; /* special start actions from adopt_locks() */
|
||||
|
||||
/*
|
||||
@@ -735,6 +735,8 @@ static const char *op_str(int x)
|
||||
return "dump_log";
|
||||
case LD_OP_DUMP_INFO:
|
||||
return "dump_info";
|
||||
case LD_OP_BUSY:
|
||||
return "busy";
|
||||
default:
|
||||
return "op_unknown";
|
||||
};
|
||||
@@ -873,14 +875,14 @@ static int lm_rem_lockspace(struct lockspace *ls, struct action *act, int free_v
|
||||
}
|
||||
|
||||
static int lm_lock(struct lockspace *ls, struct resource *r, int mode, struct action *act,
|
||||
uint32_t *r_version, int *retry, int adopt)
|
||||
struct val_blk *vb_out, int *retry, int adopt)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if (ls->lm_type == LD_LM_DLM)
|
||||
rv = lm_lock_dlm(ls, r, mode, r_version, adopt);
|
||||
rv = lm_lock_dlm(ls, r, mode, vb_out, adopt);
|
||||
else if (ls->lm_type == LD_LM_SANLOCK)
|
||||
rv = lm_lock_sanlock(ls, r, mode, r_version, retry, adopt);
|
||||
rv = lm_lock_sanlock(ls, r, mode, vb_out, retry, adopt);
|
||||
else
|
||||
return -1;
|
||||
|
||||
@@ -926,7 +928,7 @@ static int lm_unlock(struct lockspace *ls, struct resource *r, struct action *ac
|
||||
static int lm_hosts(struct lockspace *ls, int notify)
|
||||
{
|
||||
if (ls->lm_type == LD_LM_DLM)
|
||||
return 0;
|
||||
return lm_hosts_dlm(ls, notify);
|
||||
else if (ls->lm_type == LD_LM_SANLOCK)
|
||||
return lm_hosts_sanlock(ls, notify);
|
||||
return -1;
|
||||
@@ -959,6 +961,13 @@ static int lm_find_free_lock(struct lockspace *ls, uint64_t *free_offset)
|
||||
|
||||
static void add_client_result(struct action *act)
|
||||
{
|
||||
if (act->flags & LD_AF_NO_CLIENT) {
|
||||
log_debug("internal action done op %s mode %s result %d vg %s",
|
||||
op_str(act->op), mode_str(act->mode), act->result, act->vg_name);
|
||||
free_action(act);
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&client_mutex);
|
||||
if (act->flags & LD_AF_ADOPT)
|
||||
list_add_tail(&act->list, &adopt_results);
|
||||
@@ -1015,13 +1024,19 @@ static void add_work_action(struct action *act)
|
||||
static int res_lock(struct lockspace *ls, struct resource *r, struct action *act, int *retry)
|
||||
{
|
||||
struct lock *lk;
|
||||
uint32_t r_version = 0;
|
||||
int rv;
|
||||
struct val_blk vb;
|
||||
uint32_t new_version = 0;
|
||||
int inval_meta;
|
||||
int rv = 0;
|
||||
|
||||
memset(&vb, 0, sizeof(vb));
|
||||
|
||||
r->last_client_id = act->client_id;
|
||||
|
||||
if (r->type == LD_RT_LV)
|
||||
log_debug("S %s R %s res_lock mode %s (%s)", ls->name, r->name, mode_str(act->mode), act->lv_name);
|
||||
log_debug("S %s R %s res_lock cl %u mode %s (%s)", ls->name, r->name, act->client_id, mode_str(act->mode), act->lv_name);
|
||||
else
|
||||
log_debug("S %s R %s res_lock mode %s", ls->name, r->name, mode_str(act->mode));
|
||||
log_debug("S %s R %s res_lock cl %u mode %s", ls->name, r->name, act->client_id, mode_str(act->mode));
|
||||
|
||||
if (r->mode == LD_LK_SH && act->mode == LD_LK_SH)
|
||||
goto add_lk;
|
||||
@@ -1029,114 +1044,245 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
|
||||
if (r->type == LD_RT_LV && act->lv_args[0])
|
||||
memcpy(r->lv_args, act->lv_args, MAX_ARGS);
|
||||
|
||||
rv = lm_lock(ls, r, act->mode, act, &r_version, retry, act->flags & LD_AF_ADOPT);
|
||||
if (rv == -EAGAIN)
|
||||
return rv;
|
||||
if (rv < 0) {
|
||||
log_error("S %s R %s res_lock lm error %d", ls->name, r->name, rv);
|
||||
return rv;
|
||||
}
|
||||
rv = lm_lock(ls, r, act->mode, act, &vb, retry, act->flags & LD_AF_ADOPT);
|
||||
|
||||
log_debug("S %s R %s res_lock lm done r_version %u",
|
||||
ls->name, r->name, r_version);
|
||||
if (r->use_vb)
|
||||
log_debug("S %s R %s res_lock rv %d read vb %x %x %u",
|
||||
ls->name, r->name, rv, vb.version, vb.flags, vb.r_version);
|
||||
else
|
||||
log_debug("S %s R %s res_lock rv %d", ls->name, r->name, rv);
|
||||
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
if (sanlock_gl_dup && ls->sanlock_gl_enabled)
|
||||
act->flags |= LD_AF_DUP_GL_LS;
|
||||
|
||||
/* lm_lock() reads new r_version */
|
||||
/*
|
||||
* Check new lvb values to decide if lvmetad cache should
|
||||
* be invalidated. When we need to invalidate the lvmetad
|
||||
* cache, but don't have a usable r_version from the lvb,
|
||||
* send lvmetad new_version 0 which causes it to invalidate
|
||||
* the VG metdata without comparing against the currently
|
||||
* cached VG seqno.
|
||||
*/
|
||||
|
||||
if ((r_version != r->version) || (!r->version && !r->version_zero_valid)) {
|
||||
inval_meta = 0;
|
||||
|
||||
if (!r->use_vb) {
|
||||
/* LV locks don't use an lvb. */
|
||||
|
||||
} else if (vb.version && ((vb.version & 0xFF00) > (VAL_BLK_VERSION & 0xFF00))) {
|
||||
log_error("S %s R %s res_lock invalid val_blk version %x flags %x r_version %u",
|
||||
ls->name, r->name, vb.version, vb.flags, vb.r_version);
|
||||
inval_meta = 1;
|
||||
new_version = 0;
|
||||
rv = -EINVAL;
|
||||
|
||||
} else if (vb.r_version && (vb.r_version == r->version)) {
|
||||
/*
|
||||
* r_version only increases, so if it goes down, it means the
|
||||
* dlm lvb became invalid (happens during recovery if the
|
||||
* resource master leaves).
|
||||
* Common case when the version hasn't changed.
|
||||
* Do nothing.
|
||||
*/
|
||||
if (r_version < r->version) {
|
||||
log_debug("S %s R %s res_lock lvb invalid r_version %u prev %u",
|
||||
ls->name, r->name, r_version, r->version);
|
||||
} else if (r->version && vb.r_version && (vb.r_version > r->version)) {
|
||||
/*
|
||||
* Common case when the version has changed. Another host
|
||||
* has changed the data protected by the lock since we last
|
||||
* acquired it, and increased r_version so we know that our
|
||||
* cache is invalid.
|
||||
*/
|
||||
log_debug("S %s R %s res_lock got version %u our %u",
|
||||
ls->name, r->name, vb.r_version, r->version);
|
||||
r->version = vb.r_version;
|
||||
new_version = vb.r_version;
|
||||
r->version_zero_valid = 0;
|
||||
inval_meta = 1;
|
||||
|
||||
} else if (r->version_zero_valid && !vb.r_version) {
|
||||
/*
|
||||
* The lvb is in a persistent zero state, which will end
|
||||
* once someone uses the lock and writes a new lvb value.
|
||||
* Do nothing.
|
||||
*/
|
||||
log_debug("S %s R %s res_lock version_zero_valid still zero", ls->name, r->name);
|
||||
|
||||
} else if (r->version_zero_valid && vb.r_version) {
|
||||
/*
|
||||
* Someone has written to the lvb after it was in a
|
||||
* persistent zero state. Begin tracking normal
|
||||
* non-zero changes. We may or may not have known
|
||||
* about a previous non-zero version (in r->version).
|
||||
* If we did, it means the lvb content was lost and
|
||||
* has now been reinitialized.
|
||||
*
|
||||
* If the new reinitialized value is less than the
|
||||
* previous non-zero value in r->version, then something
|
||||
* unusual has happened. For a VG lock, it probably
|
||||
* means the VG was removed and recreated. Invalidate
|
||||
* our cache and begin using the new VG version. For
|
||||
* a GL lock, another host may have reinitialized a
|
||||
* lost/zero lvb with a value less than we'd seen
|
||||
* before. Invalidate the cache, and begin using
|
||||
* the lower version (or continue using our old
|
||||
* larger version?)
|
||||
*/
|
||||
if (r->version && (r->version >= vb.r_version)) {
|
||||
log_debug("S %s R %s res_lock version_zero_valid got version %u less than our %u",
|
||||
ls->name, r->name, vb.r_version, r->version);
|
||||
new_version = 0;
|
||||
} else {
|
||||
log_debug("S %s R %s res_lock version_zero_valid got version %u our %u",
|
||||
ls->name, r->name, vb.r_version, r->version);
|
||||
new_version = vb.r_version;
|
||||
}
|
||||
r->version = vb.r_version;
|
||||
r->version_zero_valid = 0;
|
||||
inval_meta = 1;
|
||||
|
||||
} else if (!r->version && vb.r_version) {
|
||||
/*
|
||||
* New r_version of the lock: means that another
|
||||
* host has changed data protected by this lock
|
||||
* since the last time we acquired it. We
|
||||
* should invalidate any local cache of the data
|
||||
* protected by this lock and reread it from disk.
|
||||
* The first time we've acquired the lock and seen the lvb.
|
||||
*/
|
||||
r->version = r_version;
|
||||
log_debug("S %s R %s res_lock initial version %u", ls->name, r->name, vb.r_version);
|
||||
r->version = vb.r_version;
|
||||
inval_meta = 1;
|
||||
new_version = vb.r_version;
|
||||
r->version_zero_valid = 0;
|
||||
|
||||
} else if (!r->version && !vb.r_version) {
|
||||
/*
|
||||
* When a new global lock is enabled in a new vg,
|
||||
* it will have version zero, and the first time
|
||||
* we use it we need to validate the global cache
|
||||
* since we don't have any version history to know
|
||||
* the state of the cache. The version could remain
|
||||
* zero for a long time if no global state is changed
|
||||
* to cause the GL version to be incremented to 1.
|
||||
* The lock may have never been used to change something.
|
||||
* (e.g. a new sanlock GL?)
|
||||
*/
|
||||
log_debug("S %s R %s res_lock all versions zero", ls->name, r->name);
|
||||
if (!r->version_zero_valid) {
|
||||
inval_meta = 1;
|
||||
new_version = 0;
|
||||
}
|
||||
r->version_zero_valid = 1;
|
||||
|
||||
} else if (r->version && !vb.r_version) {
|
||||
/*
|
||||
* r is vglk: tell lvmetad to set the vg invalid
|
||||
* flag, and provide the new r_version. If lvmetad finds
|
||||
* that its cached vg has seqno less than the value
|
||||
* we send here, it will set the vg invalid flag.
|
||||
* lvm commands that read the vg from lvmetad, will
|
||||
* see the invalid flag returned, will reread the
|
||||
* vg from disk, update the lvmetad copy, and go on.
|
||||
* The lvb content has been lost or never been initialized.
|
||||
* It can be lost during dlm recovery when the master node
|
||||
* is removed.
|
||||
*
|
||||
* r is global: tell lvmetad to set the global invalid
|
||||
* flag. When commands see this flag returned from lvmetad,
|
||||
* they will reread metadata from disk, update the lvmetad
|
||||
* caches, and tell lvmetad to set global invalid to 0.
|
||||
* If we're the next to write the lvb, reinitialze it to the
|
||||
* new VG seqno, or a new GL counter larger than was seen by
|
||||
* any hosts before (how to estimate that?)
|
||||
*
|
||||
* If we see non-zero values before we next write to it, use
|
||||
* those values.
|
||||
*
|
||||
* While the lvb values remain zero, the data for the lock
|
||||
* is unchanged and we don't need to invalidate metadata.
|
||||
*/
|
||||
if ((ls->lm_type == LD_LM_DLM) && !vb.version && !vb.flags)
|
||||
log_debug("S %s R %s res_lock all lvb content is blank",
|
||||
ls->name, r->name);
|
||||
log_debug("S %s R %s res_lock our version %u got vb %x %x %u",
|
||||
ls->name, r->name, r->version, vb.version, vb.flags, vb.r_version);
|
||||
r->version_zero_valid = 1;
|
||||
inval_meta = 1;
|
||||
new_version = 0;
|
||||
|
||||
if ((r->type == LD_RT_VG) && lvmetad_connected) {
|
||||
daemon_reply reply;
|
||||
char *uuid;
|
||||
} else if (r->version && vb.r_version && (vb.r_version < r->version)) {
|
||||
/*
|
||||
* The lvb value has gone backwards, which shouldn't generally happen,
|
||||
* but could when the dlm lvb is lost and reinitialized, or the VG
|
||||
* is removed and recreated.
|
||||
*
|
||||
* If this is a VG lock, it probably means the VG has been removed
|
||||
* and recreated while we had the dlm lockspace running.
|
||||
* FIXME: how does the cache validation and replacement in lvmetad
|
||||
* work in this case?
|
||||
*/
|
||||
log_debug("S %s R %s res_lock got version %u less than our version %u",
|
||||
ls->name, r->name, vb.r_version, r->version);
|
||||
r->version = vb.r_version;
|
||||
inval_meta = 1;
|
||||
new_version = 0;
|
||||
r->version_zero_valid = 0;
|
||||
} else {
|
||||
log_debug("S %s R %s res_lock undefined vb condition vzv %d our version %u vb %x %x %u",
|
||||
ls->name, r->name, r->version_zero_valid, r->version,
|
||||
vb.version, vb.flags, vb.r_version);
|
||||
}
|
||||
|
||||
log_debug("S %s R %s res_lock set lvmetad vg version %u",
|
||||
ls->name, r->name, r_version);
|
||||
if (vb.version && vb.r_version && (vb.flags & VBF_REMOVED)) {
|
||||
/* Should we set ls->thread_stop = 1 ? */
|
||||
log_debug("S %s R %s res_lock vb flag REMOVED",
|
||||
ls->name, r->name);
|
||||
rv = -EREMOVED;
|
||||
}
|
||||
|
||||
if (!lvmetad_connected && inval_meta)
|
||||
log_debug("S %s R %s res_lock no lvmetad connection to invalidate",
|
||||
ls->name, r->name);
|
||||
|
||||
/*
|
||||
* r is vglk: tell lvmetad to set the vg invalid
|
||||
* flag, and provide the new r_version. If lvmetad finds
|
||||
* that its cached vg has seqno less than the value
|
||||
* we send here, it will set the vg invalid flag.
|
||||
* lvm commands that read the vg from lvmetad, will
|
||||
* see the invalid flag returned, will reread the
|
||||
* vg from disk, update the lvmetad copy, and go on.
|
||||
*
|
||||
* r is global: tell lvmetad to set the global invalid
|
||||
* flag. When commands see this flag returned from lvmetad,
|
||||
* they will reread metadata from disk, update the lvmetad
|
||||
* caches, and tell lvmetad to set global invalid to 0.
|
||||
*/
|
||||
|
||||
if (lvmetad_connected && inval_meta && (r->type == LD_RT_VG)) {
|
||||
daemon_reply reply;
|
||||
char *uuid;
|
||||
|
||||
log_debug("S %s R %s res_lock set lvmetad vg version %u",
|
||||
ls->name, r->name, new_version);
|
||||
|
||||
if (!ls->vg_uuid[0] || !strcmp(ls->vg_uuid, "none"))
|
||||
uuid = (char *)"none";
|
||||
else
|
||||
uuid = ls->vg_uuid;
|
||||
if (!ls->vg_uuid[0] || !strcmp(ls->vg_uuid, "none"))
|
||||
uuid = (char *)"none";
|
||||
else
|
||||
uuid = ls->vg_uuid;
|
||||
|
||||
pthread_mutex_lock(&lvmetad_mutex);
|
||||
reply = daemon_send_simple(lvmetad_handle, "set_vg_info",
|
||||
"token = %s", "skip",
|
||||
"uuid = %s", uuid,
|
||||
"name = %s", ls->vg_name,
|
||||
"version = %d", (int)r_version,
|
||||
NULL);
|
||||
pthread_mutex_lock(&lvmetad_mutex);
|
||||
reply = daemon_send_simple(lvmetad_handle, "set_vg_info",
|
||||
"token = %s", "skip",
|
||||
"uuid = %s", uuid,
|
||||
"name = %s", ls->vg_name,
|
||||
"version = %d", (int)new_version,
|
||||
NULL);
|
||||
pthread_mutex_unlock(&lvmetad_mutex);
|
||||
|
||||
if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK"))
|
||||
log_error("set_vg_info in lvmetad failed %d", reply.error);
|
||||
daemon_reply_destroy(reply);
|
||||
}
|
||||
if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK"))
|
||||
log_error("set_vg_info in lvmetad failed %d", reply.error);
|
||||
daemon_reply_destroy(reply);
|
||||
}
|
||||
|
||||
if ((r->type == LD_RT_GL) && lvmetad_connected) {
|
||||
daemon_reply reply;
|
||||
if (lvmetad_connected && inval_meta && (r->type == LD_RT_GL)) {
|
||||
daemon_reply reply;
|
||||
|
||||
log_debug("S %s R %s res_lock set lvmetad global invalid",
|
||||
ls->name, r->name);
|
||||
log_debug("S %s R %s res_lock set lvmetad global invalid",
|
||||
ls->name, r->name);
|
||||
|
||||
pthread_mutex_lock(&lvmetad_mutex);
|
||||
reply = daemon_send_simple(lvmetad_handle, "set_global_info",
|
||||
pthread_mutex_lock(&lvmetad_mutex);
|
||||
reply = daemon_send_simple(lvmetad_handle, "set_global_info",
|
||||
"token = %s", "skip",
|
||||
"global_invalid = %d", 1,
|
||||
NULL);
|
||||
pthread_mutex_unlock(&lvmetad_mutex);
|
||||
pthread_mutex_unlock(&lvmetad_mutex);
|
||||
|
||||
if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK"))
|
||||
log_error("set_global_info in lvmetad failed %d", reply.error);
|
||||
daemon_reply_destroy(reply);
|
||||
}
|
||||
if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK"))
|
||||
log_error("set_global_info in lvmetad failed %d", reply.error);
|
||||
daemon_reply_destroy(reply);
|
||||
}
|
||||
|
||||
/*
|
||||
* Record the new lock state.
|
||||
*/
|
||||
|
||||
r->mode = act->mode;
|
||||
|
||||
add_lk:
|
||||
@@ -1154,9 +1300,29 @@ add_lk:
|
||||
lk->client_id = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* LV_LOCK means the action acquired the lv lock in the lock manager
|
||||
* (as opposed to finding that the lv lock was already held). If
|
||||
* the client for this LV_LOCK action fails before we send the result,
|
||||
* then we automatically unlock the lv since the lv wasn't activated.
|
||||
* (There will always be an odd chance the lv lock is held while the
|
||||
* lv is not active, but this helps.) The most common case where this
|
||||
* is helpful is when the lv lock operation is slow/delayed and the
|
||||
* command is canceled by the user.
|
||||
*
|
||||
* LV_UNLOCK means the lv unlock action was generated by lvmlockd when
|
||||
* it tried to send the reply for an lv lock action (with LV_LOCK set),
|
||||
* and failed to send the reply to the client/command. The
|
||||
* last_client_id saved on the resource is compared to this LV_UNLOCK
|
||||
* action before the auto unlock is done in case another action locked
|
||||
* the lv between the failed client lock action and the auto unlock.
|
||||
*/
|
||||
if (r->type == LD_RT_LV)
|
||||
act->flags |= LD_AF_LV_LOCK;
|
||||
|
||||
list_add_tail(&lk->list, &r->locks);
|
||||
|
||||
return 0;
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int res_convert(struct lockspace *ls, struct resource *r,
|
||||
@@ -1165,7 +1331,9 @@ static int res_convert(struct lockspace *ls, struct resource *r,
|
||||
uint32_t r_version;
|
||||
int rv;
|
||||
|
||||
log_debug("S %s R %s res_convert mode %d", ls->name, r->name, act->mode);
|
||||
r->last_client_id = act->client_id;
|
||||
|
||||
log_debug("S %s R %s res_convert cl %u mode %d", ls->name, r->name, act->client_id, act->mode);
|
||||
|
||||
if (act->mode == LD_LK_EX && lk->mode == LD_LK_SH && r->sh_count > 1)
|
||||
return -EAGAIN;
|
||||
@@ -1243,7 +1411,7 @@ static int res_cancel(struct lockspace *ls, struct resource *r,
|
||||
return -ENOENT;
|
||||
|
||||
do_cancel:
|
||||
log_debug("S %s R %s res_cancel client %d", ls->name, r->name, cact->client_id);
|
||||
log_debug("S %s R %s res_cancel cl %u", ls->name, r->name, cact->client_id);
|
||||
cact->result = -ECANCELED;
|
||||
list_del(&cact->list);
|
||||
add_client_result(cact);
|
||||
@@ -1291,34 +1459,46 @@ static int res_unlock(struct lockspace *ls, struct resource *r,
|
||||
}
|
||||
|
||||
if (act->op != LD_OP_CLOSE)
|
||||
log_debug("S %s R %s res_unlock no locks", ls->name, r->name);
|
||||
log_debug("S %s R %s res_unlock cl %u no locks", ls->name, r->name, act->client_id);
|
||||
return -ENOENT;
|
||||
|
||||
do_unlock:
|
||||
if ((act->flags & LD_AF_LV_UNLOCK) && (r->last_client_id != act->client_id)) {
|
||||
log_debug("S %s R %s res_unlock cl %u for failed client ignored, last client %u",
|
||||
ls->name, r->name, act->client_id, r->last_client_id);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
r->last_client_id = act->client_id;
|
||||
|
||||
if (act->op == LD_OP_CLOSE)
|
||||
log_debug("S %s R %s res_unlock from close", ls->name, r->name);
|
||||
log_debug("S %s R %s res_unlock cl %u from close", ls->name, r->name, act->client_id);
|
||||
else if (r->type == LD_RT_LV)
|
||||
log_debug("S %s R %s res_unlock (%s)", ls->name, r->name, act->lv_name);
|
||||
log_debug("S %s R %s res_unlock cl %u (%s)", ls->name, r->name, act->client_id, act->lv_name);
|
||||
else
|
||||
log_debug("S %s R %s res_unlock", ls->name, r->name);
|
||||
log_debug("S %s R %s res_unlock cl %u", ls->name, r->name, act->client_id);
|
||||
|
||||
/* send unlock to lm when last sh lock is unlocked */
|
||||
if (lk->mode == LD_LK_SH) {
|
||||
r->sh_count--;
|
||||
if (r->sh_count > 0)
|
||||
if (r->sh_count > 0) {
|
||||
log_debug("S %s R %s res_unlock sh_count %u", ls->name, r->name, r->sh_count);
|
||||
goto rem_lk;
|
||||
}
|
||||
}
|
||||
|
||||
if ((r->type == LD_RT_GL) && (r->mode == LD_LK_EX)) {
|
||||
r->version++;
|
||||
lk->version = r->version;
|
||||
r_version = r->version;
|
||||
r->version_zero_valid = 0;
|
||||
|
||||
log_debug("S %s R %s res_unlock r_version inc %u", ls->name, r->name, r_version);
|
||||
|
||||
} else if ((r->type == LD_RT_VG) && (r->mode == LD_LK_EX) && (lk->version > r->version)) {
|
||||
r->version = lk->version;
|
||||
r_version = r->version;
|
||||
r->version_zero_valid = 0;
|
||||
|
||||
log_debug("S %s R %s res_unlock r_version new %u",
|
||||
ls->name, r->name, r_version);
|
||||
@@ -1352,14 +1532,14 @@ static int res_update(struct lockspace *ls, struct resource *r,
|
||||
|
||||
lk = find_lock_client(r, act->client_id);
|
||||
if (!lk) {
|
||||
log_error("S %s R %s res_update client %u lock not found",
|
||||
log_error("S %s R %s res_update cl %u lock not found",
|
||||
ls->name, r->name, act->client_id);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (r->mode != LD_LK_EX) {
|
||||
log_error("S %s R %s res_update version on non-ex lock",
|
||||
ls->name, r->name);
|
||||
log_error("S %s R %s res_update cl %u version on non-ex lock",
|
||||
ls->name, r->name, act->client_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -1370,7 +1550,7 @@ static int res_update(struct lockspace *ls, struct resource *r,
|
||||
else
|
||||
lk->version = act->version;
|
||||
|
||||
log_debug("S %s R %s res_update lk version to %u", ls->name, r->name, lk->version);
|
||||
log_debug("S %s R %s res_update cl %u lk version to %u", ls->name, r->name, act->client_id, lk->version);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1570,6 +1750,7 @@ static void res_process(struct lockspace *ls, struct resource *r,
|
||||
continue;
|
||||
} else {
|
||||
/* success */
|
||||
r->last_client_id = act->client_id;
|
||||
act->result = -EALREADY;
|
||||
list_del(&act->list);
|
||||
add_client_result(act);
|
||||
@@ -1604,6 +1785,7 @@ static void res_process(struct lockspace *ls, struct resource *r,
|
||||
continue;
|
||||
} else {
|
||||
/* success */
|
||||
r->last_client_id = act->client_id;
|
||||
act->result = -EALREADY;
|
||||
list_del(&act->list);
|
||||
add_client_result(act);
|
||||
@@ -1641,6 +1823,7 @@ static void res_process(struct lockspace *ls, struct resource *r,
|
||||
|
||||
if ((lk->mode == LD_LK_EX) ||
|
||||
(lk->mode == LD_LK_SH && act->mode == LD_LK_SH)) {
|
||||
r->last_client_id = act->client_id;
|
||||
act->result = 0;
|
||||
list_del(&act->list);
|
||||
add_client_result(act);
|
||||
@@ -1648,6 +1831,7 @@ static void res_process(struct lockspace *ls, struct resource *r,
|
||||
/* persistent lock is sh, transient request is ex */
|
||||
/* FIXME: can we remove this case? do a convert here? */
|
||||
log_debug("res_process %s existing persistent lock new transient", r->name);
|
||||
r->last_client_id = act->client_id;
|
||||
act->result = -EEXIST;
|
||||
list_del(&act->list);
|
||||
add_client_result(act);
|
||||
@@ -1682,10 +1866,12 @@ static void res_process(struct lockspace *ls, struct resource *r,
|
||||
if (lk->mode != act->mode) {
|
||||
/* FIXME: convert and change to persistent? */
|
||||
log_debug("res_process %s existing transient lock new persistent", r->name);
|
||||
r->last_client_id = act->client_id;
|
||||
act->result = -EEXIST;
|
||||
list_del(&act->list);
|
||||
add_client_result(act);
|
||||
} else {
|
||||
r->last_client_id = act->client_id;
|
||||
lk->flags |= LD_LF_PERSISTENT;
|
||||
lk->client_id = 0;
|
||||
act->result = 0;
|
||||
@@ -1734,7 +1920,6 @@ static void res_process(struct lockspace *ls, struct resource *r,
|
||||
* lv lock conflicts won't be transient so don't retry them.
|
||||
*/
|
||||
|
||||
|
||||
if (r->mode == LD_LK_EX)
|
||||
return;
|
||||
|
||||
@@ -1960,15 +2145,18 @@ static struct resource *find_resource_act(struct lockspace *ls,
|
||||
return NULL;
|
||||
|
||||
r->type = act->rt;
|
||||
|
||||
r->mode = LD_LK_UN;
|
||||
|
||||
if (r->type == LD_RT_GL)
|
||||
if (r->type == LD_RT_GL) {
|
||||
strncpy(r->name, R_NAME_GL, MAX_NAME);
|
||||
else if (r->type == LD_RT_VG)
|
||||
r->use_vb = 1;
|
||||
} else if (r->type == LD_RT_VG) {
|
||||
strncpy(r->name, R_NAME_VG, MAX_NAME);
|
||||
else if (r->type == LD_RT_LV)
|
||||
r->use_vb = 1;
|
||||
} else if (r->type == LD_RT_LV) {
|
||||
strncpy(r->name, act->lv_uuid, MAX_NAME);
|
||||
r->use_vb = 0;
|
||||
}
|
||||
|
||||
list_add_tail(&r->list, &ls->resources);
|
||||
|
||||
@@ -2217,6 +2405,18 @@ static void *lockspace_thread_main(void *arg_in)
|
||||
break;
|
||||
}
|
||||
|
||||
if (act->op == LD_OP_BUSY && act->rt == LD_RT_VG) {
|
||||
log_debug("S %s checking if lockspace is busy", ls->name);
|
||||
rv = lm_hosts(ls, 0);
|
||||
if (rv)
|
||||
act->result = -EBUSY;
|
||||
else
|
||||
act->result = 0;
|
||||
list_del(&act->list);
|
||||
add_client_result(act);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (act->op == LD_OP_RENAME_BEFORE && act->rt == LD_RT_VG) {
|
||||
/* vgrename */
|
||||
log_debug("S %s checking for lockspace hosts", ls->name);
|
||||
@@ -2399,6 +2599,8 @@ out_act:
|
||||
ls->thread_done = 1;
|
||||
ls->free_vg = free_vg;
|
||||
ls->drop_vg = drop_vg;
|
||||
if (ls->lm_type == LD_LM_DLM && !strcmp(ls->name, gl_lsname_dlm))
|
||||
global_dlm_lockspace_exists = 0;
|
||||
pthread_mutex_unlock(&lockspaces_mutex);
|
||||
|
||||
/* worker_thread will join this thread, and free the ls */
|
||||
@@ -2495,14 +2697,10 @@ static int add_lockspace_thread(const char *ls_name,
|
||||
{
|
||||
struct lockspace *ls, *ls2;
|
||||
struct resource *r;
|
||||
uint32_t version = 0;
|
||||
int rv;
|
||||
|
||||
if (act)
|
||||
version = act->version;
|
||||
|
||||
log_debug("add_lockspace_thread %s %s version %u",
|
||||
lm_str(lm_type), ls_name, version);
|
||||
lm_str(lm_type), ls_name, act ? act->version : 0);
|
||||
|
||||
if (!(ls = alloc_lockspace()))
|
||||
return -ENOMEM;
|
||||
@@ -2532,7 +2730,7 @@ static int add_lockspace_thread(const char *ls_name,
|
||||
|
||||
r->type = LD_RT_VG;
|
||||
r->mode = LD_LK_UN;
|
||||
r->version = version;
|
||||
r->use_vb = 1;
|
||||
strncpy(r->name, R_NAME_VG, MAX_NAME);
|
||||
list_add_tail(&r->list, &ls->resources);
|
||||
|
||||
@@ -2559,6 +2757,8 @@ static int add_lockspace_thread(const char *ls_name,
|
||||
if (act)
|
||||
list_add(&act->list, &ls->actions);
|
||||
|
||||
if (ls->lm_type == LD_LM_DLM && !strcmp(ls->name, gl_lsname_dlm))
|
||||
global_dlm_lockspace_exists = 1;
|
||||
list_add_tail(&ls->list, &lockspaces);
|
||||
pthread_mutex_unlock(&lockspaces_mutex);
|
||||
|
||||
@@ -2586,15 +2786,25 @@ static int add_dlm_global_lockspace(struct action *act)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if (global_dlm_lockspace_exists)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* FIXME: optimize this by setting a flag to indicate that the
|
||||
* dlm global lockspace is running so we can quit here.
|
||||
* FIXME: if the dlm global lockspace is started without a global
|
||||
* lock request, insert an internal gl sh lock request?
|
||||
*/
|
||||
|
||||
rv = add_lockspace_thread(gl_lsname_dlm, NULL, NULL, LD_LM_DLM, NULL, act);
|
||||
if (rv < 0)
|
||||
log_debug("add_dlm_global_lockspace add_lockspace_thread %d", rv);
|
||||
|
||||
/*
|
||||
* EAGAIN may be returned for a short period because
|
||||
* global_dlm_lockspace_exists is set to 0 before the
|
||||
* ls is removed from the lockspaces list by the
|
||||
* worker_thread.
|
||||
*/
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -3320,14 +3530,14 @@ static void client_resume(struct client *cl)
|
||||
|
||||
if (!cl->poll_ignore || cl->fd == -1 || cl->pi == -1) {
|
||||
/* shouldn't happen */
|
||||
log_error("client_resume %d bad state ig %d fd %d pi %d",
|
||||
log_error("client_resume %u bad state ig %d fd %d pi %d",
|
||||
cl->id, cl->poll_ignore, cl->fd, cl->pi);
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&pollfd_mutex);
|
||||
if (pollfd[cl->pi].fd != POLL_FD_IGNORE) {
|
||||
log_error("client_resume %d pi %d fd %d not IGNORE",
|
||||
log_error("client_resume %u pi %d fd %d not IGNORE",
|
||||
cl->id, cl->pi, cl->fd);
|
||||
}
|
||||
pollfd[cl->pi].fd = cl->fd;
|
||||
@@ -3338,16 +3548,17 @@ static void client_resume(struct client *cl)
|
||||
}
|
||||
|
||||
/* called from client_thread, cl->mutex is held */
|
||||
static void client_send_result(struct client *cl, struct action *act)
|
||||
static int client_send_result(struct client *cl, struct action *act)
|
||||
{
|
||||
response res;
|
||||
char result_flags[128];
|
||||
int dump_len = 0;
|
||||
int dump_fd = -1;
|
||||
int rv = 0;
|
||||
|
||||
if (cl->dead) {
|
||||
log_debug("client send %d skip dead", cl->id);
|
||||
return;
|
||||
log_debug("send cl %u skip dead", cl->id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(result_flags, 0, sizeof(result_flags));
|
||||
@@ -3409,7 +3620,7 @@ static void client_send_result(struct client *cl, struct action *act)
|
||||
if (act->lv_args[0])
|
||||
lv_args = act->lv_args;
|
||||
|
||||
log_debug("send %s[%d.%u] %s %s rv %d vg_args %s lv_args %s",
|
||||
log_debug("send %s[%d] cl %u %s %s rv %d vg_args %s lv_args %s",
|
||||
cl->name[0] ? cl->name : "client", cl->pid, cl->id,
|
||||
op_str(act->op), rt_str(act->rt),
|
||||
act->result, vg_args ? vg_args : "", lv_args ? lv_args : "");
|
||||
@@ -3441,7 +3652,7 @@ static void client_send_result(struct client *cl, struct action *act)
|
||||
else
|
||||
act->result = -EINVAL;
|
||||
|
||||
log_debug("send %s[%d.%u] dump result %d dump_len %d",
|
||||
log_debug("send %s[%d] cl %u dump result %d dump_len %d",
|
||||
cl->name[0] ? cl->name : "client", cl->pid, cl->id,
|
||||
act->result, dump_len);
|
||||
|
||||
@@ -3454,7 +3665,7 @@ static void client_send_result(struct client *cl, struct action *act)
|
||||
* A normal reply.
|
||||
*/
|
||||
|
||||
log_debug("send %s[%d.%u] %s %s rv %d %s %s",
|
||||
log_debug("send %s[%d] cl %u %s %s rv %d %s %s",
|
||||
cl->name[0] ? cl->name : "client", cl->pid, cl->id,
|
||||
op_str(act->op), rt_str(act->rt),
|
||||
act->result, (act->result == -ENOLS) ? "ENOLS" : "", result_flags);
|
||||
@@ -3468,7 +3679,13 @@ static void client_send_result(struct client *cl, struct action *act)
|
||||
NULL);
|
||||
}
|
||||
|
||||
buffer_write(cl->fd, &res.buffer);
|
||||
if (!buffer_write(cl->fd, &res.buffer)) {
|
||||
rv = -errno;
|
||||
if (rv >= 0)
|
||||
rv = -1;
|
||||
log_debug("send cl %u fd %d error %d", cl->id, cl->fd, rv);
|
||||
}
|
||||
|
||||
buffer_destroy(&res.buffer);
|
||||
|
||||
client_resume(cl);
|
||||
@@ -3478,6 +3695,8 @@ static void client_send_result(struct client *cl, struct action *act)
|
||||
send_dump_buf(dump_fd, dump_len);
|
||||
close(dump_fd);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* called from client_thread */
|
||||
@@ -3603,17 +3822,6 @@ static int add_lock_action(struct action *act)
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&ls->mutex);
|
||||
if (ls->thread_stop && ls->thread_done) {
|
||||
log_debug("lockspace is done finish cleanup %s", ls_name);
|
||||
pthread_join(ls->thread, NULL);
|
||||
list_del(&ls->list);
|
||||
pthread_mutex_unlock(&ls->mutex);
|
||||
free_ls_resources(ls);
|
||||
free(ls);
|
||||
pthread_mutex_unlock(&lockspaces_mutex);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (ls->thread_stop) {
|
||||
pthread_mutex_unlock(&ls->mutex);
|
||||
pthread_mutex_unlock(&lockspaces_mutex);
|
||||
@@ -3679,6 +3887,11 @@ static int str_to_op_rt(const char *req_name, int *op, int *rt)
|
||||
*rt = LD_RT_VG;
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(req_name, "busy_vg")) {
|
||||
*op = LD_OP_BUSY;
|
||||
*rt = LD_RT_VG;
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(req_name, "free_lv")) {
|
||||
*op = LD_OP_FREE;
|
||||
*rt = LD_RT_LV;
|
||||
@@ -4138,10 +4351,10 @@ static void client_recv_action(struct client *cl)
|
||||
rv = buffer_read(cl->fd, &req.buffer);
|
||||
if (!rv) {
|
||||
if (errno == ECONNRESET) {
|
||||
log_debug("client recv %d ECONNRESET", cl->id);
|
||||
log_debug("client recv %u ECONNRESET", cl->id);
|
||||
cl->dead = 1;
|
||||
} else {
|
||||
log_error("client recv %d buffer_read error %d", cl->id, errno);
|
||||
log_error("client recv %u buffer_read error %d", cl->id, errno);
|
||||
}
|
||||
buffer_destroy(&req.buffer);
|
||||
client_resume(cl);
|
||||
@@ -4150,7 +4363,7 @@ static void client_recv_action(struct client *cl)
|
||||
|
||||
req.cft = dm_config_from_string(req.buffer.mem);
|
||||
if (!req.cft) {
|
||||
log_error("client recv %d config_from_string error", cl->id);
|
||||
log_error("client recv %u config_from_string error", cl->id);
|
||||
buffer_destroy(&req.buffer);
|
||||
client_resume(cl);
|
||||
return;
|
||||
@@ -4159,7 +4372,7 @@ static void client_recv_action(struct client *cl)
|
||||
str = daemon_request_str(req, "request", NULL);
|
||||
rv = str_to_op_rt(str, &op, &rt);
|
||||
if (rv < 0) {
|
||||
log_error("client recv %d bad request name \"%s\"", cl->id, str ? str : "");
|
||||
log_error("client recv %u bad request name \"%s\"", cl->id, str ? str : "");
|
||||
dm_config_destroy(req.cft);
|
||||
buffer_destroy(&req.buffer);
|
||||
client_resume(cl);
|
||||
@@ -4282,7 +4495,7 @@ static void client_recv_action(struct client *cl)
|
||||
dm_config_destroy(req.cft);
|
||||
buffer_destroy(&req.buffer);
|
||||
|
||||
log_debug("recv %s[%d.%u] %s %s \"%s\" mode %s flags %x",
|
||||
log_debug("recv %s[%d] cl %u %s %s \"%s\" mode %s flags %x",
|
||||
cl->name[0] ? cl->name : "client", cl->pid, cl->id,
|
||||
op_str(act->op), rt_str(act->rt), act->vg_name, mode_str(act->mode), opts);
|
||||
|
||||
@@ -4331,6 +4544,7 @@ static void client_recv_action(struct client *cl)
|
||||
case LD_OP_FIND_FREE_LOCK:
|
||||
case LD_OP_KILL_VG:
|
||||
case LD_OP_DROP_VG:
|
||||
case LD_OP_BUSY:
|
||||
rv = add_lock_action(act);
|
||||
break;
|
||||
default:
|
||||
@@ -4348,6 +4562,8 @@ static void *client_thread_main(void *arg_in)
|
||||
{
|
||||
struct client *cl;
|
||||
struct action *act;
|
||||
struct action *act_un;
|
||||
int rv;
|
||||
|
||||
while (1) {
|
||||
pthread_mutex_lock(&client_mutex);
|
||||
@@ -4371,11 +4587,30 @@ static void *client_thread_main(void *arg_in)
|
||||
|
||||
if (cl) {
|
||||
pthread_mutex_lock(&cl->mutex);
|
||||
client_send_result(cl, act);
|
||||
rv = client_send_result(cl, act);
|
||||
pthread_mutex_unlock(&cl->mutex);
|
||||
} else {
|
||||
log_debug("no client for result");
|
||||
log_debug("no client %u for result", act->client_id);
|
||||
rv = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The client failed after we acquired an LV lock for
|
||||
* it, but before getting this reply saying it's done.
|
||||
* So the lv will not be active and we should release
|
||||
* the lv lock it requested.
|
||||
*/
|
||||
if ((rv < 0) && (act->flags & LD_AF_LV_LOCK)) {
|
||||
log_debug("auto unlock lv for failed client %u", act->client_id);
|
||||
if ((act_un = alloc_action())) {
|
||||
memcpy(act_un, act, sizeof(struct action));
|
||||
act_un->mode = LD_LK_UN;
|
||||
act_un->flags |= LD_AF_LV_UNLOCK;
|
||||
act_un->flags &= ~LD_AF_LV_LOCK;
|
||||
add_lock_action(act_un);
|
||||
}
|
||||
}
|
||||
|
||||
free_action(act);
|
||||
continue;
|
||||
}
|
||||
@@ -4405,6 +4640,7 @@ static void *client_thread_main(void *arg_in)
|
||||
log_debug("client rem %d pi %d fd %d ig %d",
|
||||
cl->id, cl->pi, cl->fd, cl->poll_ignore);
|
||||
*/
|
||||
|
||||
/*
|
||||
* If cl->dead was set in main_loop, then the
|
||||
* fd has already been closed and the pollfd
|
||||
@@ -4627,6 +4863,7 @@ static int get_lockd_vgs(struct list_head *vg_lockd)
|
||||
goto next;
|
||||
}
|
||||
|
||||
r->use_vb = 0;
|
||||
r->type = LD_RT_LV;
|
||||
strncpy(r->name, lv_uuid, MAX_NAME);
|
||||
if (lock_args)
|
||||
@@ -5047,7 +5284,7 @@ static void adopt_locks(void)
|
||||
act->flags = (LD_AF_ADOPT | LD_AF_WAIT);
|
||||
act->rt = LD_RT_GL;
|
||||
act->lm_type = LD_LM_DLM;
|
||||
act->client_id = ADOPT_CLIENT_ID;
|
||||
act->client_id = INTERNAL_CLIENT_ID;
|
||||
add_dlm_global_lockspace(act);
|
||||
count_start++;
|
||||
}
|
||||
@@ -5059,7 +5296,7 @@ static void adopt_locks(void)
|
||||
act->flags = (LD_AF_ADOPT | LD_AF_WAIT);
|
||||
act->rt = LD_RT_VG;
|
||||
act->lm_type = ls->lm_type;
|
||||
act->client_id = ADOPT_CLIENT_ID;
|
||||
act->client_id = INTERNAL_CLIENT_ID;
|
||||
strncpy(act->vg_name, ls->vg_name, MAX_NAME);
|
||||
memcpy(act->vg_uuid, ls->vg_uuid, 64);
|
||||
memcpy(act->vg_args, ls->vg_args, MAX_ARGS);
|
||||
@@ -5151,7 +5388,7 @@ static void adopt_locks(void)
|
||||
act->rt = LD_RT_LV;
|
||||
act->mode = LD_LK_EX;
|
||||
act->flags = (LD_AF_ADOPT | LD_AF_PERSISTENT);
|
||||
act->client_id = ADOPT_CLIENT_ID;
|
||||
act->client_id = INTERNAL_CLIENT_ID;
|
||||
act->lm_type = ls->lm_type;
|
||||
strncpy(act->vg_name, ls->vg_name, MAX_NAME);
|
||||
strncpy(act->lv_uuid, r->name, MAX_NAME);
|
||||
@@ -5179,7 +5416,7 @@ static void adopt_locks(void)
|
||||
act->rt = LD_RT_VG;
|
||||
act->mode = LD_LK_SH;
|
||||
act->flags = LD_AF_ADOPT;
|
||||
act->client_id = ADOPT_CLIENT_ID;
|
||||
act->client_id = INTERNAL_CLIENT_ID;
|
||||
act->lm_type = ls->lm_type;
|
||||
strncpy(act->vg_name, ls->vg_name, MAX_NAME);
|
||||
|
||||
@@ -5205,7 +5442,7 @@ static void adopt_locks(void)
|
||||
act->rt = LD_RT_GL;
|
||||
act->mode = LD_LK_SH;
|
||||
act->flags = LD_AF_ADOPT;
|
||||
act->client_id = ADOPT_CLIENT_ID;
|
||||
act->client_id = INTERNAL_CLIENT_ID;
|
||||
act->lm_type = (gl_use_sanlock ? LD_LM_SANLOCK : LD_LM_DLM);
|
||||
|
||||
log_debug("adopt lock for gl");
|
||||
@@ -5444,7 +5681,7 @@ static void process_listener(int poll_fd)
|
||||
pthread_mutex_lock(&client_mutex);
|
||||
client_ids++;
|
||||
|
||||
if (client_ids == ADOPT_CLIENT_ID)
|
||||
if (client_ids == INTERNAL_CLIENT_ID)
|
||||
client_ids++;
|
||||
if (!client_ids)
|
||||
client_ids++;
|
||||
@@ -5453,7 +5690,7 @@ static void process_listener(int poll_fd)
|
||||
list_add_tail(&cl->list, &client_list);
|
||||
pthread_mutex_unlock(&client_mutex);
|
||||
|
||||
log_debug("client add id %d pi %d fd %d", cl->id, cl->pi, cl->fd);
|
||||
log_debug("new cl %u pi %d fd %d", cl->id, cl->pi, cl->fd);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -5596,14 +5833,14 @@ static int main_loop(daemon_state *ds_arg)
|
||||
|
||||
if (cl->recv) {
|
||||
/* should not happen */
|
||||
log_error("main client %d already recv", cl->id);
|
||||
log_error("main client %u already recv", cl->id);
|
||||
|
||||
} else if (cl->dead) {
|
||||
/* should not happen */
|
||||
log_error("main client %d already dead", cl->id);
|
||||
log_error("main client %u already dead", cl->id);
|
||||
|
||||
} else if (is_dead) {
|
||||
log_debug("close %s[%d.%u] fd %d",
|
||||
log_debug("close %s[%d] cl %u fd %d",
|
||||
cl->name[0] ? cl->name : "client",
|
||||
cl->pid, cl->id, cl->fd);
|
||||
cl->dead = 1;
|
||||
|
||||
@@ -343,7 +343,7 @@ static int to_dlm_mode(int ld_mode)
|
||||
}
|
||||
|
||||
static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
uint32_t *r_version)
|
||||
struct val_blk *vb_out)
|
||||
{
|
||||
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
||||
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
||||
@@ -352,7 +352,7 @@ static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
int mode;
|
||||
int rv;
|
||||
|
||||
*r_version = 0;
|
||||
memset(vb_out, 0, sizeof(struct val_blk));
|
||||
|
||||
if (!r->lm_init) {
|
||||
rv = lm_add_resource_dlm(ls, r, 0);
|
||||
@@ -431,15 +431,13 @@ 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,
|
||||
uint32_t *r_version, int adopt)
|
||||
struct val_blk *vb_out, int adopt)
|
||||
{
|
||||
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
||||
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
||||
struct dlm_lksb *lksb;
|
||||
struct val_blk vb;
|
||||
uint32_t flags = 0;
|
||||
uint16_t vb_version;
|
||||
uint16_t vb_flags;
|
||||
int mode;
|
||||
int rv;
|
||||
|
||||
@@ -447,7 +445,7 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
/* When adopting, we don't follow the normal method
|
||||
of acquiring a NL lock then converting it to the
|
||||
desired mode. */
|
||||
return lm_adopt_dlm(ls, r, ld_mode, r_version);
|
||||
return lm_adopt_dlm(ls, r, ld_mode, vb_out);
|
||||
}
|
||||
|
||||
if (!r->lm_init) {
|
||||
@@ -475,7 +473,7 @@ 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);
|
||||
|
||||
if (daemon_test) {
|
||||
*r_version = 0;
|
||||
memset(vb_out, 0, sizeof(struct val_blk));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -513,35 +511,22 @@ lockrv:
|
||||
if (lksb->sb_flags & DLM_SBF_VALNOTVALID) {
|
||||
log_debug("S %s R %s lock_dlm VALNOTVALID", ls->name, r->name);
|
||||
memset(rdd->vb, 0, sizeof(struct val_blk));
|
||||
*r_version = 0;
|
||||
memset(vb_out, 0, sizeof(struct val_blk));
|
||||
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));
|
||||
vb_version = le16_to_cpu(vb.version);
|
||||
vb_flags = le16_to_cpu(vb.flags);
|
||||
memcpy(rdd->vb, &vb, sizeof(vb));
|
||||
|
||||
if (vb_version && ((vb_version & 0xFF00) > (VAL_BLK_VERSION & 0xFF00))) {
|
||||
log_error("S %s R %s lock_dlm ignore vb_version %x",
|
||||
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 flags %x",
|
||||
ls->name, r->name, *r_version, vb_flags);
|
||||
|
||||
if (vb_flags & VBF_REMOVED) {
|
||||
log_debug("S %s R %s lock_dlm VG has been removed",
|
||||
ls->name, r->name);
|
||||
return -EREMOVED;
|
||||
}
|
||||
vb_out->version = le16_to_cpu(vb.version);
|
||||
vb_out->flags = le16_to_cpu(vb.flags);
|
||||
vb_out->r_version = le32_to_cpu(vb.r_version);
|
||||
}
|
||||
out:
|
||||
return 0;
|
||||
@@ -602,12 +587,12 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
||||
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
||||
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
||||
struct dlm_lksb *lksb = &rdd->lksb;
|
||||
struct val_blk vb_prev;
|
||||
struct val_blk vb_next;
|
||||
uint32_t flags = 0;
|
||||
int new_vb = 0;
|
||||
int rv;
|
||||
|
||||
log_debug("S %s R %s unlock_dlm r_version %u flags %x",
|
||||
ls->name, r->name, r_version, lmu_flags);
|
||||
|
||||
/*
|
||||
* Do not set PERSISTENT, because we don't need an orphan
|
||||
* NL lock to protect anything.
|
||||
@@ -616,22 +601,45 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
||||
flags |= LKF_CONVERT;
|
||||
|
||||
if (rdd->vb && (r->mode == LD_LK_EX)) {
|
||||
if (!rdd->vb->version) {
|
||||
/* first time vb has been written */
|
||||
rdd->vb->version = cpu_to_le16(VAL_BLK_VERSION);
|
||||
|
||||
/* vb_prev and vb_next are in disk endian form */
|
||||
memcpy(&vb_prev, rdd->vb, sizeof(struct val_blk));
|
||||
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);
|
||||
|
||||
if ((lmu_flags & LMUF_FREE_VG) && (r->type == LD_RT_VG))
|
||||
rdd->vb->flags = cpu_to_le16(VBF_REMOVED);
|
||||
if ((lmu_flags & LMUF_FREE_VG) && (r->type == LD_RT_VG)) {
|
||||
vb_next.flags = cpu_to_le16(VBF_REMOVED);
|
||||
new_vb = 1;
|
||||
}
|
||||
|
||||
memcpy(lksb->sb_lvbptr, rdd->vb, sizeof(struct val_blk));
|
||||
if (r_version) {
|
||||
vb_next.r_version = cpu_to_le32(r_version);
|
||||
new_vb = 1;
|
||||
}
|
||||
|
||||
log_debug("S %s R %s unlock_dlm set r_version %u",
|
||||
ls->name, r->name, r_version);
|
||||
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;
|
||||
} else {
|
||||
log_debug("S %s R %s unlock_dlm", ls->name, r->name);
|
||||
}
|
||||
|
||||
if (daemon_test)
|
||||
@@ -654,6 +662,62 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
||||
|
||||
#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;
|
||||
|
||||
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)
|
||||
{
|
||||
static const char closedir_err_msg[] = "lm_get_lockspace_dlm: closedir failed";
|
||||
@@ -700,3 +764,4 @@ int lm_is_running_dlm(void)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ enum {
|
||||
LD_OP_FIND_FREE_LOCK,
|
||||
LD_OP_KILL_VG,
|
||||
LD_OP_DROP_VG,
|
||||
LD_OP_BUSY,
|
||||
};
|
||||
|
||||
/* resource types */
|
||||
@@ -89,7 +90,7 @@ struct client {
|
||||
};
|
||||
|
||||
#define LD_AF_PERSISTENT 0x00000001
|
||||
#define LD_AF_UNUSED 0x00000002 /* use me */
|
||||
#define LD_AF_NO_CLIENT 0x00000002
|
||||
#define LD_AF_UNLOCK_CANCEL 0x00000004
|
||||
#define LD_AF_NEXT_VERSION 0x00000008
|
||||
#define LD_AF_WAIT 0x00000010
|
||||
@@ -102,6 +103,8 @@ struct client {
|
||||
#define LD_AF_DUP_GL_LS 0x00002000
|
||||
#define LD_AF_ADOPT 0x00010000
|
||||
#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
|
||||
@@ -140,12 +143,13 @@ struct resource {
|
||||
int8_t mode;
|
||||
unsigned int sh_count; /* number of sh locks on locks list */
|
||||
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 adopt : 1; /* temp flag in remove_inactive_lvs */
|
||||
unsigned int version_zero_valid : 1;
|
||||
unsigned int use_vb : 1;
|
||||
struct list_head locks;
|
||||
struct list_head actions;
|
||||
struct val_blk *vb;
|
||||
char lv_args[MAX_ARGS+1];
|
||||
char lm_data[0]; /* lock manager specific data */
|
||||
};
|
||||
@@ -316,10 +320,9 @@ static inline int list_empty(const struct list_head *head)
|
||||
EXTERN int gl_type_static;
|
||||
EXTERN int gl_use_dlm;
|
||||
EXTERN int gl_use_sanlock;
|
||||
EXTERN pthread_mutex_t gl_type_mutex;
|
||||
|
||||
EXTERN char gl_lsname_dlm[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_debug;
|
||||
@@ -356,7 +359,7 @@ int lm_prepare_lockspace_dlm(struct lockspace *ls);
|
||||
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt);
|
||||
int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg);
|
||||
int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
uint32_t *r_version, int adopt);
|
||||
struct val_blk *vb_out, int adopt);
|
||||
int lm_convert_dlm(struct lockspace *ls, struct resource *r,
|
||||
int ld_mode, uint32_t r_version);
|
||||
int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
||||
@@ -365,6 +368,7 @@ int lm_rem_resource_dlm(struct lockspace *ls, struct resource *r);
|
||||
int lm_get_lockspaces_dlm(struct list_head *ls_rejoin);
|
||||
int lm_data_size_dlm(void);
|
||||
int lm_is_running_dlm(void);
|
||||
int lm_hosts_dlm(struct lockspace *ls, int notify);
|
||||
|
||||
static inline int lm_support_dlm(void)
|
||||
{
|
||||
@@ -394,7 +398,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,
|
||||
uint32_t *r_version, int adopt)
|
||||
struct val_blk *vb_out, int adopt)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@@ -436,6 +440,11 @@ static inline int lm_support_dlm(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int lm_hosts_dlm(struct lockspace *ls, int notify)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* dlm support */
|
||||
|
||||
#ifdef LOCKDSANLOCK_SUPPORT
|
||||
@@ -448,7 +457,7 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls);
|
||||
int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt);
|
||||
int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg);
|
||||
int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
uint32_t *r_version, int *retry, int adopt);
|
||||
struct val_blk *vb_out, int *retry, int adopt);
|
||||
int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
|
||||
int ld_mode, uint32_t r_version);
|
||||
int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
|
||||
@@ -506,7 +515,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,
|
||||
uint32_t *r_version, int *retry, int adopt)
|
||||
struct val_blk *vb_out, int *retry, int adopt)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1300,7 +1300,7 @@ int lm_rem_resource_sanlock(struct lockspace *ls, struct resource *r)
|
||||
}
|
||||
|
||||
int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
uint32_t *r_version, int *retry, int adopt)
|
||||
struct val_blk *vb_out, int *retry, int adopt)
|
||||
{
|
||||
struct lm_sanlock *lms = (struct lm_sanlock *)ls->lm_data;
|
||||
struct rd_sanlock *rds = (struct rd_sanlock *)r->lm_data;
|
||||
@@ -1308,7 +1308,6 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
uint64_t lock_lv_offset;
|
||||
uint32_t flags = 0;
|
||||
struct val_blk vb;
|
||||
uint16_t vb_version;
|
||||
int added = 0;
|
||||
int rv;
|
||||
|
||||
@@ -1384,7 +1383,7 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
(unsigned long long)rs->disks[0].offset);
|
||||
|
||||
if (daemon_test) {
|
||||
*r_version = 0;
|
||||
memset(vb_out, 0, sizeof(struct val_blk));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1393,6 +1392,15 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
if (adopt)
|
||||
flags |= SANLK_ACQUIRE_ORPHAN_ONLY;
|
||||
|
||||
#ifdef SANLOCK_HAS_ACQUIRE_OWNER_NOWAIT
|
||||
/*
|
||||
* Don't block waiting for a failed lease to expire since it causes
|
||||
* sanlock_acquire to block for a long time, which would prevent this
|
||||
* thread from processing other lock requests.
|
||||
*/
|
||||
flags |= SANLK_ACQUIRE_OWNER_NOWAIT;
|
||||
#endif
|
||||
|
||||
rv = sanlock_acquire(lms->sock, -1, flags, 1, &rs, NULL);
|
||||
|
||||
if (rv == -EAGAIN) {
|
||||
@@ -1463,6 +1471,26 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
#ifdef SANLOCK_HAS_ACQUIRE_OWNER_NOWAIT
|
||||
if (rv == SANLK_ACQUIRE_OWNED_RETRY) {
|
||||
/*
|
||||
* The lock is held by a failed host, and will eventually
|
||||
* expire. If we retry we'll eventually acquire the lock
|
||||
* (or find someone else has acquired it). The EAGAIN retry
|
||||
* attempts for SH locks above would not be sufficient for
|
||||
* the length of expiration time. We could add a longer
|
||||
* retry time here to cover the full expiration time and block
|
||||
* the activation command for that long. For now just return
|
||||
* the standard error indicating that another host still owns
|
||||
* the lease. FIXME: return a different error number so the
|
||||
* command can print an different error indicating that the
|
||||
* owner of the lease is in the process of expiring?
|
||||
*/
|
||||
log_debug("S %s R %s lock_san acquire mode %d rv %d", ls->name, r->name, ld_mode, rv);
|
||||
*retry = 0;
|
||||
return -EAGAIN;
|
||||
}
|
||||
#endif
|
||||
if (rv < 0) {
|
||||
log_error("S %s R %s lock_san acquire error %d",
|
||||
ls->name, r->name, rv);
|
||||
@@ -1501,26 +1529,23 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
rv = sanlock_get_lvb(0, rs, (char *)&vb, sizeof(vb));
|
||||
if (rv < 0) {
|
||||
log_error("S %s R %s lock_san get_lvb error %d", ls->name, r->name, rv);
|
||||
*r_version = 0;
|
||||
memset(rds->vb, 0, sizeof(struct val_blk));
|
||||
memset(vb_out, 0, sizeof(struct val_blk));
|
||||
goto out;
|
||||
}
|
||||
|
||||
vb_version = le16_to_cpu(vb.version);
|
||||
/*
|
||||
* 'vb' contains disk endian values, not host endian.
|
||||
* It is copied directly to rrs->vb which is also kept
|
||||
* in disk endian form.
|
||||
* vb_out is returned to the caller in host endian form.
|
||||
*/
|
||||
|
||||
if (vb_version && ((vb_version & 0xFF00) > (VAL_BLK_VERSION & 0xFF00))) {
|
||||
log_error("S %s R %s lock_san ignore vb_version %x",
|
||||
ls->name, r->name, vb_version);
|
||||
*r_version = 0;
|
||||
free(rds->vb);
|
||||
rds->vb = NULL;
|
||||
goto out;
|
||||
}
|
||||
memcpy(rds->vb, &vb, sizeof(vb));
|
||||
|
||||
*r_version = le32_to_cpu(vb.r_version);
|
||||
memcpy(rds->vb, &vb, sizeof(vb)); /* rds->vb saved as le */
|
||||
|
||||
log_debug("S %s R %s lock_san get r_version %u",
|
||||
ls->name, r->name, *r_version);
|
||||
vb_out->version = le16_to_cpu(vb.version);
|
||||
vb_out->flags = le16_to_cpu(vb.flags);
|
||||
vb_out->r_version = le32_to_cpu(vb.r_version);
|
||||
}
|
||||
out:
|
||||
return rv;
|
||||
|
||||
@@ -45,7 +45,6 @@
|
||||
@top_srcdir@/lib/metadata/vg.h
|
||||
@top_srcdir@/lib/mm/memlock.h
|
||||
@top_srcdir@/lib/mm/xlate.h
|
||||
@top_builddir@/lib/misc/configure.h
|
||||
@top_srcdir@/lib/misc/crc.h
|
||||
@top_srcdir@/lib/misc/intl.h
|
||||
@top_srcdir@/lib/misc/last-path-component.h
|
||||
@@ -56,7 +55,6 @@
|
||||
@top_srcdir@/lib/misc/lvm-globals.h
|
||||
@top_srcdir@/lib/misc/lvm-signal.h
|
||||
@top_srcdir@/lib/misc/lvm-string.h
|
||||
@top_builddir@/lib/misc/lvm-version.h
|
||||
@top_srcdir@/lib/misc/lvm-percent.h
|
||||
@top_srcdir@/lib/misc/lvm-wrappers.h
|
||||
@top_srcdir@/lib/misc/sharedlib.h
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#
|
||||
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
# Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
|
||||
# Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of LVM2.
|
||||
#
|
||||
@@ -35,5 +35,5 @@ device-mapper: all
|
||||
|
||||
cflow: all
|
||||
|
||||
DISTCLEAN_TARGETS += .symlinks
|
||||
DISTCLEAN_TARGETS += .symlinks configure.h lvm-version.h
|
||||
CLEAN_TARGETS += $(LINKS) .include_symlinks .symlinks_created
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* lib/misc/configure.h.in. Generated from configure.in by autoheader. */
|
||||
/* include/configure.h.in. Generated from configure.in by autoheader. */
|
||||
|
||||
/* Define to 1 to use libblkid detection of signatures when wiping. */
|
||||
#undef BLKID_WIPING_SUPPORT
|
||||
@@ -62,6 +62,7 @@ SOURCES =\
|
||||
device/dev-swap.c \
|
||||
device/dev-type.c \
|
||||
device/dev-luks.c \
|
||||
device/dev-dasd.c \
|
||||
display/display.c \
|
||||
error/errseg.c \
|
||||
unknown/unknown.c \
|
||||
@@ -230,4 +231,4 @@ CFLAGS += $(BLKID_CFLAGS) $(UDEV_CFLAGS) $(VALGRIND_CFLAGS)
|
||||
|
||||
$(SUBDIRS): $(LIB_STATIC)
|
||||
|
||||
DISTCLEAN_TARGETS += misc/configure.h misc/lvm-version.h
|
||||
CLEAN_TARGETS += misc/configure.h misc/lvm-version.h
|
||||
|
||||
@@ -143,23 +143,23 @@ static int _get_segment_status_from_target_params(const char *target_name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(segtype->name, "cache")) {
|
||||
if (segtype_is_cache(segtype)) {
|
||||
if (!dm_get_status_cache(seg_status->mem, params, &(seg_status->cache)))
|
||||
return_0;
|
||||
seg_status->type = SEG_STATUS_CACHE;
|
||||
} else if (!strcmp(segtype->name, "raid")) {
|
||||
} else if (segtype_is_raid(segtype)) {
|
||||
if (!dm_get_status_raid(seg_status->mem, params, &seg_status->raid))
|
||||
return_0;
|
||||
seg_status->type = SEG_STATUS_RAID;
|
||||
} else if (!strcmp(segtype->name, "thin")) {
|
||||
} else if (segtype_is_thin_volume(segtype)) {
|
||||
if (!dm_get_status_thin(seg_status->mem, params, &seg_status->thin))
|
||||
return_0;
|
||||
seg_status->type = SEG_STATUS_THIN;
|
||||
} else if (!strcmp(segtype->name, "thin-pool")) {
|
||||
} else if (segtype_is_thin_pool(segtype)) {
|
||||
if (!dm_get_status_thin_pool(seg_status->mem, params, &seg_status->thin_pool))
|
||||
return_0;
|
||||
seg_status->type = SEG_STATUS_THIN_POOL;
|
||||
} else if (!strcmp(segtype->name, "snapshot")) {
|
||||
} else if (segtype_is_snapshot(segtype)) {
|
||||
if (!dm_get_status_snapshot(seg_status->mem, params, &seg_status->snapshot))
|
||||
return_0;
|
||||
seg_status->type = SEG_STATUS_SNAPSHOT;
|
||||
@@ -3277,7 +3277,7 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
|
||||
break;
|
||||
case SUSPEND:
|
||||
dm_tree_skip_lockfs(root);
|
||||
if (!dm->flush_required && lv_is_mirror(lv) && !lv_is_pvmove(lv))
|
||||
if (!dm->flush_required && !lv_is_pvmove(lv))
|
||||
dm_tree_use_no_flush_suspend(root);
|
||||
/* Fall through */
|
||||
case SUSPEND_WITH_LOCKFS:
|
||||
@@ -3296,7 +3296,14 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
|
||||
if (!dm_tree_preload_children(root, dlid, DLID_SIZE))
|
||||
goto_out;
|
||||
|
||||
if (dm_tree_node_size_changed(root))
|
||||
if ((dm_tree_node_size_changed(root) < 0))
|
||||
dm->flush_required = 1;
|
||||
|
||||
/* Currently keep the code require flush for any
|
||||
* non 'thin pool/volume, mirror' or with any size change */
|
||||
if (!lv_is_thin_volume(lv) &&
|
||||
!lv_is_thin_pool(lv) &&
|
||||
(!lv_is_mirror(lv) || dm_tree_node_size_changed(root)))
|
||||
dm->flush_required = 1;
|
||||
|
||||
if (action == ACTIVATE) {
|
||||
|
||||
32
lib/cache/lvmcache.c
vendored
32
lib/cache/lvmcache.c
vendored
@@ -1542,10 +1542,6 @@ int lvmcache_update_vgname_and_id(struct lvmcache_info *info, struct lvmcache_vg
|
||||
vgid = vgname;
|
||||
}
|
||||
|
||||
/* When using lvmetad, the PV could not have become orphaned. */
|
||||
if (lvmetad_active() && is_orphan_vg(vgname) && info->vginfo)
|
||||
return 1;
|
||||
|
||||
/* If PV without mdas is already in a real VG, don't make it orphan */
|
||||
if (is_orphan_vg(vgname) && info->vginfo &&
|
||||
mdas_empty_or_ignored(&info->mdas) &&
|
||||
@@ -1871,8 +1867,8 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||
* device already exists? Things don't seem to work
|
||||
* if we do that for some reason.
|
||||
*/
|
||||
log_verbose("Found same device %s with same pvid %s",
|
||||
dev_name(existing->dev), pvid_s);
|
||||
log_debug_cache("Found same device %s with same pvid %s",
|
||||
dev_name(existing->dev), pvid_s);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2358,3 +2354,27 @@ int lvmcache_contains_lock_type_sanlock(struct cmd_context *cmd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lvmcache_get_max_name_lengths(struct cmd_context *cmd,
|
||||
unsigned *pv_max_name_len,
|
||||
unsigned *vg_max_name_len)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
struct lvmcache_info *info;
|
||||
unsigned len;
|
||||
|
||||
*vg_max_name_len = 0;
|
||||
*pv_max_name_len = 0;
|
||||
|
||||
dm_list_iterate_items(vginfo, &_vginfos) {
|
||||
len = strlen(vginfo->vgname);
|
||||
if (*vg_max_name_len < len)
|
||||
*vg_max_name_len = len;
|
||||
|
||||
dm_list_iterate_items(info, &vginfo->infos) {
|
||||
len = strlen(dev_name(info->dev));
|
||||
if (*pv_max_name_len < len)
|
||||
*pv_max_name_len = len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
4
lib/cache/lvmcache.h
vendored
4
lib/cache/lvmcache.h
vendored
@@ -190,4 +190,8 @@ void lvmcache_set_preferred_duplicates(const char *vgid);
|
||||
|
||||
int lvmcache_contains_lock_type_sanlock(struct cmd_context *cmd);
|
||||
|
||||
void lvmcache_get_max_name_lengths(struct cmd_context *cmd,
|
||||
unsigned *pv_max_name_len, unsigned *vg_max_name_len);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
96
lib/cache/lvmetad.c
vendored
96
lib/cache/lvmetad.c
vendored
@@ -37,6 +37,70 @@ static struct cmd_context *_lvmetad_cmd = NULL;
|
||||
|
||||
static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg);
|
||||
|
||||
static int _log_debug_inequality(const char *name, struct dm_config_node *a, struct dm_config_node *b)
|
||||
{
|
||||
int result = 0;
|
||||
int final_result = 0;
|
||||
|
||||
if (a->v && b->v) {
|
||||
result = compare_value(a->v, b->v);
|
||||
if (result) {
|
||||
struct dm_config_value *av = a->v;
|
||||
struct dm_config_value *bv = b->v;
|
||||
|
||||
if (!strcmp(a->key, b->key)) {
|
||||
if (a->v->type == DM_CFG_STRING && b->v->type == DM_CFG_STRING)
|
||||
log_debug_lvmetad("VG %s metadata inequality at %s / %s: %s / %s",
|
||||
name, a->key, b->key, av->v.str, bv->v.str);
|
||||
else if (a->v->type == DM_CFG_INT && b->v->type == DM_CFG_INT)
|
||||
log_debug_lvmetad("VG %s metadata inequality at %s / %s: " FMTi64 " / " FMTi64,
|
||||
name, a->key, b->key, av->v.i, bv->v.i);
|
||||
else
|
||||
log_debug_lvmetad("VG %s metadata inequality at %s / %s: type %d / type %d",
|
||||
name, a->key, b->key, av->type, bv->type);
|
||||
} else {
|
||||
log_debug_lvmetad("VG %s metadata inequality at %s / %s", name, a->key, b->key);
|
||||
}
|
||||
final_result = result;
|
||||
}
|
||||
}
|
||||
|
||||
if (a->v && !b->v) {
|
||||
log_debug_lvmetad("VG %s metadata inequality at %s / %s", name, a->key, b->key);
|
||||
final_result = 1;
|
||||
}
|
||||
|
||||
if (!a->v && b->v) {
|
||||
log_debug_lvmetad("VG %s metadata inequality at %s / %s", name, a->key, b->key);
|
||||
final_result = -1;
|
||||
}
|
||||
|
||||
if (a->child && b->child) {
|
||||
result = _log_debug_inequality(name, a->child, b->child);
|
||||
if (result)
|
||||
final_result = result;
|
||||
}
|
||||
|
||||
if (a->sib && b->sib) {
|
||||
result = _log_debug_inequality(name, a->sib, b->sib);
|
||||
if (result)
|
||||
final_result = result;
|
||||
}
|
||||
|
||||
|
||||
if (a->sib && !b->sib) {
|
||||
log_debug_lvmetad("VG %s metadata inequality at %s / %s", name, a->key, b->key);
|
||||
final_result = 1;
|
||||
}
|
||||
|
||||
if (!a->sib && b->sib) {
|
||||
log_debug_lvmetad("VG %s metadata inequality at %s / %s", name, a->key, b->key);
|
||||
final_result = -1;
|
||||
}
|
||||
|
||||
return final_result;
|
||||
}
|
||||
|
||||
void lvmetad_disconnect(void)
|
||||
{
|
||||
if (_lvmetad_connected)
|
||||
@@ -1122,6 +1186,8 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
|
||||
* due to something like an lvcreate from another host.
|
||||
* This is limited to changes that only affect the vg (not global state like
|
||||
* orphan PVs), so we only need to reread mdas on the vg's existing pvs.
|
||||
* But, a previous PV in the VG may have been removed since we last read
|
||||
* the VG, and that PV may have been reused for another VG.
|
||||
*/
|
||||
|
||||
static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg)
|
||||
@@ -1134,6 +1200,7 @@ static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct vo
|
||||
struct format_instance *fid;
|
||||
struct format_instance_ctx fic = { .type = 0 };
|
||||
struct _lvmetad_pvscan_baton baton;
|
||||
struct device *save_dev = NULL;
|
||||
|
||||
dm_list_iterate_items(pvl, &vg->pvs) {
|
||||
/* missing pv */
|
||||
@@ -1160,9 +1227,25 @@ static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct vo
|
||||
|
||||
lvmcache_foreach_mda(info, _lvmetad_pvscan_single, &baton);
|
||||
|
||||
/*
|
||||
* The PV may have been removed from the VG by another host
|
||||
* since we last read the VG.
|
||||
*/
|
||||
if (!baton.vg) {
|
||||
log_debug_lvmetad("Did not find VG %s in scan of PV %s", vg->name, dev_name(pvl->pv->dev));
|
||||
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
|
||||
return NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* The PV may have been removed from the VG and used for a
|
||||
* different VG since we last read the VG.
|
||||
*/
|
||||
if (strcmp(baton.vg->name, vg->name)) {
|
||||
log_debug_lvmetad("Did not find VG %s in scan of PV %s which is now VG %s",
|
||||
vg->name, dev_name(pvl->pv->dev), baton.vg->name);
|
||||
release_vg(baton.vg);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(vgmeta = export_vg_to_config_tree(baton.vg))) {
|
||||
@@ -1173,9 +1256,12 @@ static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct vo
|
||||
|
||||
if (!vgmeta_ret) {
|
||||
vgmeta_ret = vgmeta;
|
||||
save_dev = pvl->pv->dev;
|
||||
} else {
|
||||
if (!compare_config(vgmeta_ret->root, vgmeta->root)) {
|
||||
log_error("VG metadata comparison failed");
|
||||
if (compare_config(vgmeta_ret->root, vgmeta->root)) {
|
||||
log_error("VG %s metadata comparison failed for device %s vs %s",
|
||||
vg->name, dev_name(pvl->pv->dev), save_dev ? dev_name(save_dev) : "none");
|
||||
_log_debug_inequality(vg->name, vgmeta_ret->root, vgmeta->root);
|
||||
dm_config_destroy(vgmeta);
|
||||
dm_config_destroy(vgmeta_ret);
|
||||
release_vg(baton.vg);
|
||||
@@ -1245,7 +1331,7 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
||||
log_warn("WARNING: Ignoring obsolete format of metadata (%s) on device %s when using lvmetad",
|
||||
baton.fid->fmt->name, dev_name(dev));
|
||||
else
|
||||
log_error("WARNING: Ignoring obsolete format of metadata (%s) on device %s when using lvmetad",
|
||||
log_error("Ignoring obsolete format of metadata (%s) on device %s when using lvmetad.",
|
||||
baton.fid->fmt->name, dev_name(dev));
|
||||
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
|
||||
|
||||
@@ -1597,7 +1683,7 @@ void lvmetad_validate_global_cache(struct cmd_context *cmd, int force)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!lvmetad_used())
|
||||
if (!lvmetad_active())
|
||||
return;
|
||||
|
||||
log_debug_lvmetad("Validating global lvmetad cache");
|
||||
|
||||
@@ -420,7 +420,7 @@ int init_cache_segtypes(struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
segtype->name = "cache-pool";
|
||||
segtype->name = SEG_TYPE_NAME_CACHE_POOL;
|
||||
segtype->flags = SEG_CACHE_POOL | SEG_CANNOT_BE_ZEROED | SEG_ONLY_EXCLUSIVE;
|
||||
segtype->ops = &_cache_pool_ops;
|
||||
|
||||
@@ -434,7 +434,7 @@ int init_cache_segtypes(struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
segtype->name = "cache";
|
||||
segtype->name = SEG_TYPE_NAME_CACHE;
|
||||
segtype->flags = SEG_CACHE | SEG_ONLY_EXCLUSIVE;
|
||||
segtype->ops = &_cache_ops;
|
||||
|
||||
|
||||
@@ -362,7 +362,8 @@ static void _init_logging(struct cmd_context *cmd)
|
||||
|
||||
/* Tell device-mapper about our logging */
|
||||
#ifdef DEVMAPPER_SUPPORT
|
||||
dm_log_with_errno_init(print_log);
|
||||
if (!dm_log_is_non_default())
|
||||
dm_log_with_errno_init(print_log);
|
||||
#endif
|
||||
reset_log_duplicated();
|
||||
reset_lvm_errno(1);
|
||||
@@ -1069,7 +1070,7 @@ static struct dev_filter *_init_lvmetad_filter_chain(struct cmd_context *cmd)
|
||||
nr_filt++;
|
||||
}
|
||||
|
||||
/* regex filter. Optional. */
|
||||
/* global regex filter. Optional. */
|
||||
if ((cn = find_config_tree_node(cmd, devices_global_filter_CFG, NULL))) {
|
||||
if (!(filters[nr_filt] = regex_filter_create(cn->v))) {
|
||||
log_error("Failed to create global regex device filter");
|
||||
@@ -1078,6 +1079,17 @@ static struct dev_filter *_init_lvmetad_filter_chain(struct cmd_context *cmd)
|
||||
nr_filt++;
|
||||
}
|
||||
|
||||
/* regex filter. Optional. */
|
||||
if (!lvmetad_used()) {
|
||||
if ((cn = find_config_tree_node(cmd, devices_filter_CFG, NULL))) {
|
||||
if (!(filters[nr_filt] = regex_filter_create(cn->v))) {
|
||||
log_error("Failed to create regex device filter");
|
||||
goto bad;
|
||||
}
|
||||
nr_filt++;
|
||||
}
|
||||
}
|
||||
|
||||
/* device type filter. Required. */
|
||||
if (!(filters[nr_filt] = lvm_type_filter_create(cmd->dev_types))) {
|
||||
log_error("Failed to create lvm type filter");
|
||||
@@ -1145,26 +1157,24 @@ bad:
|
||||
* md component filter -> fw raid filter
|
||||
*
|
||||
* - cmd->filter - the filter chain used for lvmetad responses:
|
||||
* persistent filter -> usable device filter(FILTER_MODE_POST_LVMETAD) ->
|
||||
* regex filter
|
||||
* persistent filter -> regex_filter -> usable device filter(FILTER_MODE_POST_LVMETAD)
|
||||
*
|
||||
* - cmd->full_filter - the filter chain used for all the remaining situations:
|
||||
* lvmetad_filter -> filter
|
||||
* cmd->lvmetad_filter -> cmd->filter
|
||||
*
|
||||
* If lvmetad isnot used, there's just one filter chain:
|
||||
* If lvmetad is not used, there's just one filter chain:
|
||||
*
|
||||
* - cmd->filter == cmd->full_filter:
|
||||
* persistent filter -> regex filter -> sysfs filter ->
|
||||
* global regex filter -> type filter ->
|
||||
* usable device filter(FILTER_MODE_NO_LVMETAD) ->
|
||||
* mpath component filter -> partitioned filter ->
|
||||
* md component filter -> fw raid filter
|
||||
* persistent filter -> sysfs filter -> global regex filter ->
|
||||
* regex_filter -> type filter -> usable device filter(FILTER_MODE_NO_LVMETAD) ->
|
||||
* mpath component filter -> partitioned filter -> md component filter -> fw raid filter
|
||||
*
|
||||
*/
|
||||
int init_filters(struct cmd_context *cmd, unsigned load_persistent_cache)
|
||||
{
|
||||
const char *dev_cache;
|
||||
struct dev_filter *filter = NULL, *filter_components[2] = {0};
|
||||
int nr_filt;
|
||||
struct stat st;
|
||||
const struct dm_config_node *cn;
|
||||
struct timespec ts, cts;
|
||||
@@ -1193,26 +1203,26 @@ int init_filters(struct cmd_context *cmd, unsigned load_persistent_cache)
|
||||
*/
|
||||
/* filter component 0 */
|
||||
if (lvmetad_used()) {
|
||||
if (!(filter_components[0] = usable_filter_create(cmd->dev_types, FILTER_MODE_POST_LVMETAD))) {
|
||||
nr_filt = 0;
|
||||
if ((cn = find_config_tree_array(cmd, devices_filter_CFG, NULL))) {
|
||||
if (!(filter_components[nr_filt] = regex_filter_create(cn->v))) {
|
||||
log_verbose("Failed to create regex device filter.");
|
||||
goto bad;
|
||||
}
|
||||
nr_filt++;
|
||||
}
|
||||
if (!(filter_components[nr_filt] = usable_filter_create(cmd->dev_types, FILTER_MODE_POST_LVMETAD))) {
|
||||
log_verbose("Failed to create usable device filter.");
|
||||
goto bad;
|
||||
}
|
||||
nr_filt++;
|
||||
if (!(filter = composite_filter_create(nr_filt, 0, filter_components)))
|
||||
goto_bad;
|
||||
} else {
|
||||
filter_components[0] = cmd->lvmetad_filter;
|
||||
filter = cmd->lvmetad_filter;
|
||||
cmd->lvmetad_filter = NULL;
|
||||
}
|
||||
|
||||
/* filter component 1 */
|
||||
if ((cn = find_config_tree_array(cmd, devices_filter_CFG, NULL))) {
|
||||
if (!(filter_components[1] = regex_filter_create(cn->v)))
|
||||
goto_bad;
|
||||
/* we have two filter components - create composite filter */
|
||||
if (!(filter = composite_filter_create(2, 0, filter_components)))
|
||||
goto_bad;
|
||||
} else
|
||||
/* we have only one filter component - no need to create composite filter */
|
||||
filter = filter_components[0];
|
||||
|
||||
if (!(dev_cache = find_config_tree_str(cmd, devices_cache_CFG, NULL)))
|
||||
goto_bad;
|
||||
|
||||
@@ -1224,9 +1234,12 @@ int init_filters(struct cmd_context *cmd, unsigned load_persistent_cache)
|
||||
cmd->filter = filter;
|
||||
|
||||
if (lvmetad_used()) {
|
||||
filter_components[0] = cmd->lvmetad_filter;
|
||||
filter_components[1] = cmd->filter;
|
||||
if (!(cmd->full_filter = composite_filter_create(2, 0, filter_components)))
|
||||
nr_filt = 0;
|
||||
filter_components[nr_filt] = cmd->lvmetad_filter;
|
||||
nr_filt++;
|
||||
filter_components[nr_filt] = cmd->filter;
|
||||
nr_filt++;
|
||||
if (!(cmd->full_filter = composite_filter_create(nr_filt, 0, filter_components)))
|
||||
goto_bad;
|
||||
} else
|
||||
cmd->full_filter = filter;
|
||||
|
||||
@@ -474,8 +474,8 @@ cfg(allocation_cache_policy_CFG, "cache_policy", allocation_CFG_SECTION, CFG_PRO
|
||||
"otherwise the older mq (Multiqueue) policy is selected.\n")
|
||||
|
||||
cfg_section(allocation_cache_settings_CFG_SECTION, "cache_settings", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, vsn(2, 2, 128), 0, NULL,
|
||||
"Individual settings for policies.\n"
|
||||
"See the help for individual policies for more info.\n")
|
||||
"Settings for the cache policy.\n"
|
||||
"See documentation for individual cache policies for more info.\n")
|
||||
|
||||
cfg_section(policy_settings_CFG_SUBSECTION, "policy_settings", allocation_cache_settings_CFG_SECTION, CFG_NAME_VARIABLE | CFG_SECTION_NO_CHECK | CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, vsn(2, 2, 128), 0, NULL,
|
||||
"Replace this subsection name with a policy name.\n"
|
||||
@@ -1416,10 +1416,20 @@ cfg(disk_area_size_CFG, "size", disk_area_CFG_SUBSECTION, CFG_UNSUPPORTED | CFG_
|
||||
cfg(disk_area_id_CFG, "id", disk_area_CFG_SUBSECTION, CFG_UNSUPPORTED | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL, NULL)
|
||||
|
||||
cfg(report_compact_output_CFG, "compact_output", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_REP_COMPACT_OUTPUT, vsn(2, 2, 115), NULL, 0, NULL,
|
||||
"Do not print empty report fields.\n"
|
||||
"Fields that don't have a value set for any of the rows reported are\n"
|
||||
"skipped and not printed. Compact output is applicable only if\n"
|
||||
"report/buffered is enabled.\n")
|
||||
"Do not print empty values for all report fields.\n"
|
||||
"If enabled, all fields that don't have a value set for any of the\n"
|
||||
"rows reported are skipped and not printed. Compact output is\n"
|
||||
"applicable only if report/buffered is enabled. If you need to\n"
|
||||
"compact only specified fields, use compact_output=0 and define\n"
|
||||
"report/compact_output_cols configuration setting instead.\n")
|
||||
|
||||
cfg(report_compact_output_cols_CFG, "compact_output_cols", report_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_COMPACT_OUTPUT_COLS, vsn(2, 2, 133), NULL, 0, NULL,
|
||||
"Do not print empty values for specified report fields.\n"
|
||||
"If defined, specified fields that don't have a value set for any\n"
|
||||
"of the rows reported are skipped and not printed. Compact output\n"
|
||||
"is applicable only if report/buffered is enabled. If you need to\n"
|
||||
"compact all fields, use compact_output=1 instead in which case\n"
|
||||
"the compact_output_cols setting is then ignored.\n")
|
||||
|
||||
cfg(report_aligned_CFG, "aligned", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_REP_ALIGNED, vsn(1, 0, 0), NULL, 0, NULL,
|
||||
"Align columns in report output.\n")
|
||||
|
||||
@@ -63,6 +63,8 @@
|
||||
#define DEFAULT_MIRROR_LOG_FAULT_POLICY "allocate"
|
||||
#define DEFAULT_MIRROR_IMAGE_FAULT_POLICY "remove"
|
||||
#define DEFAULT_MIRROR_MAX_IMAGES 8 /* limited by kernel DM_KCOPYD_MAX_REGIONS */
|
||||
#define DEFAULT_RAID_MAX_IMAGES 8
|
||||
|
||||
#define DEFAULT_RAID_FAULT_POLICY "warn"
|
||||
|
||||
#define DEFAULT_DMEVENTD_RAID_LIB "libdevmapper-event-lvm2raid.so"
|
||||
@@ -199,6 +201,8 @@
|
||||
#define DEFAULT_REP_LIST_ITEM_SEPARATOR ","
|
||||
#define DEFAULT_TIME_FORMAT "%Y-%m-%d %T %z"
|
||||
|
||||
#define DEFAULT_COMPACT_OUTPUT_COLS ""
|
||||
|
||||
#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,pool_lv,origin,data_percent,metadata_percent,move_pv,mirror_log,copy_percent,convert_lv"
|
||||
#define DEFAULT_VGS_COLS "vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free"
|
||||
#define DEFAULT_PVS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free"
|
||||
|
||||
@@ -16,11 +16,14 @@
|
||||
#include "lib.h"
|
||||
#include "str_list.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
struct dm_list *str_list_create(struct dm_pool *mem)
|
||||
{
|
||||
struct dm_list *sl;
|
||||
|
||||
if (!(sl = dm_pool_alloc(mem, sizeof(struct dm_list)))) {
|
||||
if (!(sl = mem ? dm_pool_alloc(mem, sizeof(struct dm_list))
|
||||
: dm_malloc(sizeof(struct dm_list)))) {
|
||||
log_errno(ENOMEM, "str_list allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
@@ -37,7 +40,8 @@ static int _str_list_add_no_dup_check(struct dm_pool *mem, struct dm_list *sll,
|
||||
if (!str)
|
||||
return_0;
|
||||
|
||||
if (!(sln = dm_pool_alloc(mem, sizeof(*sln))))
|
||||
if (!(sln = mem ? dm_pool_alloc(mem, sizeof(*sln))
|
||||
: dm_malloc(sizeof(*sln))))
|
||||
return_0;
|
||||
|
||||
sln->str = str;
|
||||
@@ -158,3 +162,101 @@ int str_list_lists_equal(const struct dm_list *sll, const struct dm_list *sll2)
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *str_list_to_str(struct dm_pool *mem, const struct dm_list *list,
|
||||
const char *delim)
|
||||
{
|
||||
size_t delim_len = strlen(delim);
|
||||
unsigned list_size = dm_list_size(list);
|
||||
struct dm_str_list *sl;
|
||||
char *str, *p;
|
||||
size_t len = 0;
|
||||
unsigned i = 0;
|
||||
|
||||
dm_list_iterate_items(sl, list)
|
||||
len += strlen(sl->str);
|
||||
if (list_size > 1)
|
||||
len += ((list_size - 1) * delim_len);
|
||||
|
||||
str = mem ? dm_pool_alloc(mem, len+1) : dm_malloc(len+1);
|
||||
if (!str) {
|
||||
log_error("str_list_to_str: string allocation failed.");
|
||||
return NULL;
|
||||
}
|
||||
str[len] = '\0';
|
||||
p = str;
|
||||
|
||||
dm_list_iterate_items(sl, list) {
|
||||
len = strlen(sl->str);
|
||||
memcpy(p, sl->str, len);
|
||||
p += len;
|
||||
|
||||
if (++i != list_size) {
|
||||
memcpy(p, delim, delim_len);
|
||||
p += delim_len;
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
struct dm_list *str_to_str_list(struct dm_pool *mem, const char *str,
|
||||
const char *delim, int ignore_multiple_delim)
|
||||
{
|
||||
size_t delim_len = strlen(delim);
|
||||
struct dm_list *list;
|
||||
const char *p1, *p2, *next;
|
||||
char *str_item;
|
||||
size_t len;
|
||||
|
||||
if (!(list = str_list_create(mem))) {
|
||||
log_error("str_to_str_list: string list allocation failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p1 = p2 = str;
|
||||
while (*p1) {
|
||||
if (!(p2 = strstr(p1, delim)))
|
||||
next = p2 = str + strlen(str);
|
||||
else
|
||||
next = p2 + delim_len;
|
||||
|
||||
len = p2 - p1;
|
||||
str_item = mem ? dm_pool_alloc(mem, len+1) : dm_malloc(len+1);
|
||||
if (!str_item) {
|
||||
log_error("str_to_str_list: string list item allocation failed.");
|
||||
goto bad;
|
||||
}
|
||||
memcpy(str_item, p1, len);
|
||||
str_item[len] = '\0';
|
||||
|
||||
if (!str_list_add_no_dup_check(mem, list, str_item))
|
||||
goto_bad;
|
||||
|
||||
if (ignore_multiple_delim) {
|
||||
while (!strncmp(next, delim, delim_len))
|
||||
next += delim_len;
|
||||
}
|
||||
|
||||
p1 = next;
|
||||
}
|
||||
|
||||
return list;
|
||||
bad:
|
||||
if (mem)
|
||||
dm_pool_free(mem, list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void str_list_destroy(struct dm_list *list, int deallocate_strings)
|
||||
{
|
||||
struct dm_str_list *sl, *tmp_sl;
|
||||
|
||||
dm_list_iterate_items_safe(sl, tmp_sl, list) {
|
||||
dm_list_del(&sl->list);
|
||||
if (deallocate_strings)
|
||||
dm_free((char *)sl->str);
|
||||
dm_free(sl);
|
||||
}
|
||||
dm_free(list);
|
||||
}
|
||||
|
||||
@@ -30,5 +30,9 @@ int str_list_match_list(const struct dm_list *sll, const struct dm_list *sll2, c
|
||||
int str_list_lists_equal(const struct dm_list *sll, const struct dm_list *sll2);
|
||||
int str_list_dup(struct dm_pool *mem, struct dm_list *sllnew,
|
||||
const struct dm_list *sllold);
|
||||
char *str_list_to_str(struct dm_pool *mem, const struct dm_list *list, const char *delim);
|
||||
struct dm_list *str_to_str_list(struct dm_pool *mem, const char *str, const char *delim, int ignore_multiple_delim);
|
||||
/* Only for lists which were *not* allocated from the mem pool! */
|
||||
void str_list_destroy(struct dm_list *list, int deallocate_strings);
|
||||
|
||||
#endif
|
||||
|
||||
111
lib/device/dev-dasd.c
Normal file
111
lib/device/dev-dasd.c
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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 Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "metadata.h"
|
||||
#include "dev-type.h"
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
/*
|
||||
* Interface taken from kernel header arch/s390/include/uapi/asm/dasd.h
|
||||
*/
|
||||
|
||||
/*
|
||||
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
|
||||
* Copyright IBM Corp. 1999, 2000
|
||||
* EMC Symmetrix ioctl Copyright EMC Corporation, 2008
|
||||
* Author.........: Nigel Hislop <hislop_nigel@emc.com>
|
||||
*/
|
||||
|
||||
#define DASD_IOCTL_LETTER 'D'
|
||||
#define DASD_API_VERSION 6
|
||||
|
||||
/*
|
||||
* struct dasd_information2_t
|
||||
* represents any data about the device, which is visible to userspace.
|
||||
* including foramt and featueres.
|
||||
*/
|
||||
typedef struct dasd_information2_t {
|
||||
unsigned int devno; /* S/390 devno */
|
||||
unsigned int real_devno; /* for aliases */
|
||||
unsigned int schid; /* S/390 subchannel identifier */
|
||||
unsigned int cu_type : 16; /* from SenseID */
|
||||
unsigned int cu_model : 8; /* from SenseID */
|
||||
unsigned int dev_type : 16; /* from SenseID */
|
||||
unsigned int dev_model : 8; /* from SenseID */
|
||||
unsigned int open_count;
|
||||
unsigned int req_queue_len;
|
||||
unsigned int chanq_len; /* length of chanq */
|
||||
char type[4]; /* from discipline.name, 'none' for unknown */
|
||||
unsigned int status; /* current device level */
|
||||
unsigned int label_block; /* where to find the VOLSER */
|
||||
unsigned int FBA_layout; /* fixed block size (like AIXVOL) */
|
||||
unsigned int characteristics_size;
|
||||
unsigned int confdata_size;
|
||||
char characteristics[64]; /* from read_device_characteristics */
|
||||
char configuration_data[256]; /* from read_configuration_data */
|
||||
unsigned int format; /* format info like formatted/cdl/ldl/... */
|
||||
unsigned int features; /* dasd features like 'ro',... */
|
||||
unsigned int reserved0; /* reserved for further use ,... */
|
||||
unsigned int reserved1; /* reserved for further use ,... */
|
||||
unsigned int reserved2; /* reserved for further use ,... */
|
||||
unsigned int reserved3; /* reserved for further use ,... */
|
||||
unsigned int reserved4; /* reserved for further use ,... */
|
||||
unsigned int reserved5; /* reserved for further use ,... */
|
||||
unsigned int reserved6; /* reserved for further use ,... */
|
||||
unsigned int reserved7; /* reserved for further use ,... */
|
||||
} dasd_information2_t;
|
||||
|
||||
#define DASD_FORMAT_CDL 2
|
||||
|
||||
/* Get information on a dasd device (enhanced) */
|
||||
#define BIODASDINFO2 _IOR(DASD_IOCTL_LETTER,3,dasd_information2_t)
|
||||
|
||||
/*
|
||||
* End of included interface.
|
||||
*/
|
||||
|
||||
int dasd_is_cdl_formatted(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
dasd_information2_t dasd_info2;
|
||||
|
||||
if (!dev_open_readonly(dev))
|
||||
return_0;
|
||||
|
||||
if (ioctl(dev->fd, BIODASDINFO2, &dasd_info2)) {
|
||||
log_sys_error("ioctl BIODASDINFO2", dev_name(dev));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dasd_info2.format == DASD_FORMAT_CDL)
|
||||
ret = 1;
|
||||
|
||||
out:
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int dasd_is_cdl_formatted(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -363,7 +363,7 @@ static int _native_dev_is_partitioned(struct dev_types *dt, struct device *dev)
|
||||
return 0;
|
||||
|
||||
/* Unpartitioned DASD devices are not supported. */
|
||||
if (MAJOR(dev->dev) == dt->dasd_major)
|
||||
if ((MAJOR(dev->dev) == dt->dasd_major) && dasd_is_cdl_formatted(dev))
|
||||
return 1;
|
||||
|
||||
if (!dev_open_readonly_quiet(dev)) {
|
||||
@@ -651,8 +651,13 @@ static int _wipe_known_signatures_with_blkid(struct device *dev, const char *nam
|
||||
BLKID_SUBLKS_BADCSUM);
|
||||
|
||||
while (!blkid_do_probe(probe)) {
|
||||
if ((r_wipe = _blkid_wipe(probe, dev, name, types_to_exclude, types_no_prompt, yes, force)) == 1)
|
||||
if ((r_wipe = _blkid_wipe(probe, dev, name, types_to_exclude, types_no_prompt, yes, force)) == 1) {
|
||||
(*wiped)++;
|
||||
if (blkid_probe_step_back(probe)) {
|
||||
log_error("Failed to step back blkid probe to check just wiped signature.");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
/* do not count excluded types */
|
||||
if (r_wipe != 2)
|
||||
found++;
|
||||
@@ -734,13 +739,20 @@ int wipe_known_signatures(struct cmd_context *cmd, struct device *dev,
|
||||
uint32_t types_no_prompt, int yes, force_t force,
|
||||
int *wiped)
|
||||
{
|
||||
int blkid_wiping_enabled = find_config_tree_bool(cmd, allocation_use_blkid_wiping_CFG, NULL);
|
||||
|
||||
#ifdef BLKID_WIPING_SUPPORT
|
||||
if (find_config_tree_bool(cmd, allocation_use_blkid_wiping_CFG, NULL))
|
||||
if (blkid_wiping_enabled)
|
||||
return _wipe_known_signatures_with_blkid(dev, name,
|
||||
types_to_exclude,
|
||||
types_no_prompt,
|
||||
yes, force, wiped);
|
||||
#endif
|
||||
if (blkid_wiping_enabled) {
|
||||
log_warn("allocation/use_blkid_wiping=1 configuration setting is set "
|
||||
"while LVM is not compiled with blkid wiping support.");
|
||||
log_warn("Falling back to native LVM signature detection.");
|
||||
}
|
||||
return _wipe_known_signatures_with_lvm(dev, name,
|
||||
types_to_exclude,
|
||||
types_no_prompt,
|
||||
|
||||
@@ -59,6 +59,7 @@ int major_is_scsi_device(struct dev_types *dt, int major);
|
||||
int dev_is_md(struct device *dev, uint64_t *sb);
|
||||
int dev_is_swap(struct device *dev, uint64_t *signature);
|
||||
int dev_is_luks(struct device *dev, uint64_t *signature);
|
||||
int dasd_is_cdl_formatted(struct device *dev);
|
||||
|
||||
/* Signature wiping. */
|
||||
#define TYPE_LVM1_MEMBER 0x001
|
||||
|
||||
@@ -95,7 +95,7 @@ struct segment_type *init_error_segtype(struct cmd_context *cmd)
|
||||
return_NULL;
|
||||
|
||||
segtype->ops = &_error_ops;
|
||||
segtype->name = "error";
|
||||
segtype->name = SEG_TYPE_NAME_ERROR;
|
||||
segtype->flags = SEG_CAN_SPLIT | SEG_VIRTUAL | SEG_CANNOT_BE_ZEROED;
|
||||
|
||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||
|
||||
@@ -219,7 +219,7 @@ static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
struct lv_segment *seg;
|
||||
struct segment_type *segtype;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "striped")))
|
||||
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
while (le < lvm->lv->le_count) {
|
||||
@@ -281,7 +281,7 @@ static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
|
||||
total_area_len = lvm->lv->le_count / lvm->stripes;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "striped")))
|
||||
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
while (first_area_le < total_area_len) {
|
||||
|
||||
@@ -188,8 +188,7 @@ static int _add_stripe_seg(struct dm_pool *mem,
|
||||
|
||||
area_len = (usp->devs[0].blocks) / POOL_PE_SIZE;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd,
|
||||
"striped")))
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
if (!(seg = alloc_lv_segment(segtype, lv, *le_cur,
|
||||
@@ -226,7 +225,7 @@ static int _add_linear_seg(struct dm_pool *mem,
|
||||
unsigned j;
|
||||
uint32_t area_len;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, "striped")))
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
for (j = 0; j < usp->num_devs; j++) {
|
||||
|
||||
@@ -654,7 +654,7 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
|
||||
if ((new_wrap && old_wrap) ||
|
||||
(rlocn && (new_wrap || old_wrap) && (new_end > rlocn->offset)) ||
|
||||
(mdac->rlocn.size >= mdah->size)) {
|
||||
(MDA_HEADER_SIZE + (rlocn ? rlocn->size : 0) + mdac->rlocn.size >= mdah->size)) {
|
||||
log_error("VG %s metadata too large for circular buffer",
|
||||
vg->name);
|
||||
goto out;
|
||||
@@ -1339,6 +1339,7 @@ static int _text_pv_write(const struct format_type *fmt, struct physical_volume
|
||||
|
||||
label = lvmcache_get_label(info);
|
||||
label->sector = pv->label_sector;
|
||||
label->dev = pv->dev;
|
||||
|
||||
lvmcache_update_pv(info, pv, fmt);
|
||||
|
||||
@@ -2145,7 +2146,6 @@ static int _text_pv_add_metadata_area(const struct format_type *fmt,
|
||||
goto bad;
|
||||
}
|
||||
/* Otherwise, give up and take any usable space. */
|
||||
/* FIXME: We should probably check for some minimum MDA size here. */
|
||||
else
|
||||
mda_size = limit - mda_start;
|
||||
|
||||
@@ -2242,6 +2242,12 @@ static int _text_pv_add_metadata_area(const struct format_type *fmt,
|
||||
mda_size, limit_name, limit);
|
||||
|
||||
if (mda_size) {
|
||||
if (mda_size < MDA_SIZE_MIN) {
|
||||
log_error("Metadata area size too small: %" PRIu64" bytes. "
|
||||
"It must be at least %u bytes.", mda_size, MDA_SIZE_MIN);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Wipe metadata area with zeroes. */
|
||||
if (!dev_set((struct device *) pv->dev, mda_start,
|
||||
(size_t) ((mda_size > wipe_size) ?
|
||||
|
||||
@@ -375,7 +375,7 @@ static int _read_segment(struct logical_volume *lv, const struct dm_config_node
|
||||
return 0;
|
||||
}
|
||||
|
||||
segtype_str = "striped";
|
||||
segtype_str = SEG_TYPE_NAME_STRIPED;
|
||||
|
||||
if (!dm_config_get_str(sn_child, "type", &segtype_str)) {
|
||||
log_error("Segment type must be a string.");
|
||||
|
||||
@@ -33,7 +33,7 @@ struct segment_type *init_free_segtype(struct cmd_context *cmd)
|
||||
return_NULL;
|
||||
|
||||
segtype->ops = &_freeseg_ops;
|
||||
segtype->name = "free";
|
||||
segtype->name = SEG_TYPE_NAME_FREE;
|
||||
segtype->flags = SEG_VIRTUAL | SEG_CANNOT_BE_ZEROED;
|
||||
|
||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||
|
||||
@@ -337,7 +337,7 @@ static int _create_sanlock_lv(struct cmd_context *cmd, struct volume_group *vg,
|
||||
|
||||
dm_list_init(&lp.tags);
|
||||
|
||||
if (!(lp.segtype = get_segtype_from_string(vg->cmd, "striped")))
|
||||
if (!(lp.segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
lv = lv_create_single(vg, &lp);
|
||||
@@ -698,15 +698,6 @@ static int _free_vg_dlm(struct cmd_context *cmd, struct volume_group *vg)
|
||||
if (!_lvmlockd_connected)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* For the dlm, free_vg means unlock the ex VG lock,
|
||||
* and include an indication in the lvb that the VG
|
||||
* has been removed. Then, leave the lockspace.
|
||||
* If another host tries to acquire the VG lock, it
|
||||
* will see that the VG has been removed by looking
|
||||
* at the lvb value.
|
||||
*/
|
||||
|
||||
reply = _lockd_send("free_vg",
|
||||
"pid = %d", getpid(),
|
||||
"vg_name = %s", vg->name,
|
||||
@@ -730,6 +721,50 @@ static int _free_vg_dlm(struct cmd_context *cmd, struct volume_group *vg)
|
||||
|
||||
/* called before vg_remove on disk */
|
||||
|
||||
static int _busy_vg_dlm(struct cmd_context *cmd, struct volume_group *vg)
|
||||
{
|
||||
daemon_reply reply;
|
||||
uint32_t lockd_flags = 0;
|
||||
int result;
|
||||
int ret;
|
||||
|
||||
if (!_use_lvmlockd)
|
||||
return 0;
|
||||
if (!_lvmlockd_connected)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Check that other hosts do not have the VG lockspace started.
|
||||
*/
|
||||
|
||||
reply = _lockd_send("busy_vg",
|
||||
"pid = %d", getpid(),
|
||||
"vg_name = %s", vg->name,
|
||||
"vg_lock_type = %s", vg->lock_type,
|
||||
"vg_lock_args = %s", vg->lock_args,
|
||||
NULL);
|
||||
|
||||
if (!_lockd_result(reply, &result, &lockd_flags)) {
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = (result < 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
if (result == -EBUSY) {
|
||||
log_error("Lockspace for \"%s\" not stopped on other hosts", vg->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
log_error("_busy_vg_dlm lvmlockd result %d", result);
|
||||
|
||||
out:
|
||||
daemon_reply_destroy(reply);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* called before vg_remove on disk */
|
||||
|
||||
static int _free_vg_sanlock(struct cmd_context *cmd, struct volume_group *vg)
|
||||
{
|
||||
daemon_reply reply;
|
||||
@@ -844,6 +879,9 @@ static int _lockd_all_lvs(struct cmd_context *cmd, struct volume_group *vg)
|
||||
struct lv_list *lvl;
|
||||
|
||||
dm_list_iterate_items(lvl, &vg->lvs) {
|
||||
if (!lockd_lv_uses_lock(lvl->lv))
|
||||
continue;
|
||||
|
||||
if (!lockd_lv(cmd, lvl->lv, "ex", 0)) {
|
||||
log_error("LV %s/%s must be inactive on all hosts.",
|
||||
vg->name, lvl->lv->name);
|
||||
@@ -881,8 +919,10 @@ int lockd_free_vg_before(struct cmd_context *cmd, struct volume_group *vg,
|
||||
switch (lock_type_num) {
|
||||
case LOCK_TYPE_NONE:
|
||||
case LOCK_TYPE_CLVM:
|
||||
case LOCK_TYPE_DLM:
|
||||
return 1;
|
||||
case LOCK_TYPE_DLM:
|
||||
/* returning an error will prevent vg_remove() */
|
||||
return _busy_vg_dlm(cmd, vg);
|
||||
case LOCK_TYPE_SANLOCK:
|
||||
/* returning an error will prevent vg_remove() */
|
||||
return _free_vg_sanlock(cmd, vg);
|
||||
@@ -921,9 +961,13 @@ void lockd_free_vg_final(struct cmd_context *cmd, struct volume_group *vg)
|
||||
* for starting the lockspace. To use the vg after starting
|
||||
* the lockspace, follow the standard method which is:
|
||||
* lock the vg, read/use/write the vg, unlock the vg.
|
||||
*
|
||||
* start_init is 1 when the VG is being started after the
|
||||
* command has done lockd_init_vg(). This tells lvmlockd
|
||||
* that the VG lockspace being started is new.
|
||||
*/
|
||||
|
||||
int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg)
|
||||
int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg, int start_init)
|
||||
{
|
||||
char uuid[64] __attribute__((aligned(8)));
|
||||
daemon_reply reply;
|
||||
@@ -945,8 +989,8 @@ int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug("lockd start VG %s lock_type %s",
|
||||
vg->name, vg->lock_type ? vg->lock_type : "empty");
|
||||
log_debug("lockd start VG %s lock_type %s init %d",
|
||||
vg->name, vg->lock_type ? vg->lock_type : "empty", start_init);
|
||||
|
||||
if (!id_write_format(&vg->id, uuid, sizeof(uuid)))
|
||||
return_0;
|
||||
@@ -973,6 +1017,7 @@ int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg)
|
||||
"vg_uuid = %s", uuid[0] ? uuid : "none",
|
||||
"version = %d", (int64_t)vg->seqno,
|
||||
"host_id = %d", host_id,
|
||||
"opts = %s", start_init ? "start_init" : "none",
|
||||
NULL);
|
||||
|
||||
if (!_lockd_result(reply, &result, NULL)) {
|
||||
@@ -1965,6 +2010,15 @@ int lockd_lv_name(struct cmd_context *cmd, struct volume_group *vg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (result == -EEXIST) {
|
||||
/*
|
||||
* This happens if lvchange tries to modify the LV with an ex
|
||||
* LV lock when the LV is already active with a sh LV lock.
|
||||
*/
|
||||
log_error("LV is already locked with incompatible mode: %s/%s", vg->name, lv_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (result == -EMSGSIZE) {
|
||||
/* Another host probably extended lvmlock. */
|
||||
if (!refreshed++) {
|
||||
@@ -2461,7 +2515,7 @@ int lockd_rename_vg_final(struct cmd_context *cmd, struct volume_group *vg, int
|
||||
* Depending on the problem that caused the rename to
|
||||
* fail, it may make sense to not restart the VG here.
|
||||
*/
|
||||
if (!lockd_start_vg(cmd, vg))
|
||||
if (!lockd_start_vg(cmd, vg, 0))
|
||||
log_error("Failed to restart VG %s lockspace.", vg->name);
|
||||
return 1;
|
||||
}
|
||||
@@ -2501,13 +2555,13 @@ int lockd_rename_vg_final(struct cmd_context *cmd, struct volume_group *vg, int
|
||||
}
|
||||
}
|
||||
|
||||
if (!lockd_start_vg(cmd, vg))
|
||||
if (!lockd_start_vg(cmd, vg, 1))
|
||||
log_error("Failed to start VG %s lockspace.", vg->name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *lockd_running_lock_type(struct cmd_context *cmd)
|
||||
const char *lockd_running_lock_type(struct cmd_context *cmd, int *found_multiple)
|
||||
{
|
||||
daemon_reply reply;
|
||||
const char *lock_type = NULL;
|
||||
@@ -2529,10 +2583,9 @@ const char *lockd_running_lock_type(struct cmd_context *cmd)
|
||||
|
||||
switch (result) {
|
||||
case -EXFULL:
|
||||
log_error("lvmlockd found multiple lock managers, use --lock-type to select one.");
|
||||
*found_multiple = 1;
|
||||
break;
|
||||
case -ENOLCK:
|
||||
log_error("lvmlockd found no lock manager running.");
|
||||
break;
|
||||
case LOCK_TYPE_SANLOCK:
|
||||
log_debug("lvmlockd found sanlock");
|
||||
|
||||
@@ -62,7 +62,7 @@ int lockd_rename_vg_final(struct cmd_context *cmd, struct volume_group *vg, int
|
||||
|
||||
/* start and stop the lockspace for a vg */
|
||||
|
||||
int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg);
|
||||
int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg, int start_init);
|
||||
int lockd_stop_vg(struct cmd_context *cmd, struct volume_group *vg);
|
||||
int lockd_start_wait(struct cmd_context *cmd);
|
||||
|
||||
@@ -89,7 +89,7 @@ int lockd_init_lv_args(struct cmd_context *cmd, struct volume_group *vg,
|
||||
int lockd_free_lv(struct cmd_context *cmd, struct volume_group *vg,
|
||||
const char *lv_name, struct id *lv_id, const char *lock_args);
|
||||
|
||||
const char *lockd_running_lock_type(struct cmd_context *cmd);
|
||||
const char *lockd_running_lock_type(struct cmd_context *cmd, int *found_multiple);
|
||||
|
||||
int handle_sanlock_lv(struct cmd_context *cmd, struct volume_group *vg);
|
||||
|
||||
@@ -147,7 +147,7 @@ static inline int lockd_rename_vg_final(struct cmd_context *cmd, struct volume_g
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg)
|
||||
static inline int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg, int start_init)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -223,7 +223,7 @@ static inline int lockd_free_lv(struct cmd_context *cmd, struct volume_group *vg
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline const char *lockd_running_lock_type(struct cmd_context *cmd)
|
||||
static inline const char *lockd_running_lock_type(struct cmd_context *cmd, int *found_multiple)
|
||||
{
|
||||
log_error("Using a shared lock type requires lvmlockd.");
|
||||
return NULL;
|
||||
|
||||
@@ -19,8 +19,6 @@
|
||||
#include "lvm-string.h"
|
||||
#include "activate.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
/*
|
||||
* No locking
|
||||
*/
|
||||
|
||||
@@ -49,10 +49,7 @@ static size_t _lvm_errmsg_len = 0;
|
||||
|
||||
void init_log_fn(lvm2_log_fn_t log_fn)
|
||||
{
|
||||
if (log_fn)
|
||||
_lvm2_log_fn = log_fn;
|
||||
else
|
||||
_lvm2_log_fn = NULL;
|
||||
_lvm2_log_fn = log_fn;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
#ifndef _LVM_LOGGING_H
|
||||
#define _LVM_LOGGING_H
|
||||
|
||||
__attribute__ ((format(printf, 5, 6)))
|
||||
void print_log(int level, const char *file, int line, int dm_errno_or_class,
|
||||
const char *format, ...)
|
||||
__attribute__ ((format(printf, 5, 6)));
|
||||
const char *format, ...);
|
||||
|
||||
#define LOG_LINE(l, x...) \
|
||||
print_log(l, __FILE__, __LINE__ , 0, ## x)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2014-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -101,6 +101,23 @@ int cache_set_mode(struct lv_segment *seg, const char *str)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* At least warn a user if certain cache stacks may present some problems
|
||||
*/
|
||||
void cache_check_for_warns(const struct lv_segment *seg)
|
||||
{
|
||||
struct logical_volume *origin_lv = seg_lv(seg, 0);
|
||||
|
||||
if (lv_is_raid(origin_lv) &&
|
||||
first_seg(seg->pool_lv)->feature_flags & DM_CACHE_FEATURE_WRITEBACK)
|
||||
log_warn("WARNING: Data redundancy is lost with writeback "
|
||||
"caching of raid logical volume!");
|
||||
|
||||
if (lv_is_thin_pool_data(seg->lv))
|
||||
log_warn("WARNING: Cached thin pool's data cannot be currently "
|
||||
"resized and require manual uncache before resize!");
|
||||
}
|
||||
|
||||
int update_cache_pool_params(const struct segment_type *segtype,
|
||||
struct volume_group *vg, unsigned attr,
|
||||
int passed_args, uint32_t pool_data_extents,
|
||||
@@ -244,7 +261,7 @@ struct logical_volume *lv_cache_create(struct logical_volume *pool_lv,
|
||||
if (lv_is_thin_pool(cache_lv))
|
||||
cache_lv = seg_lv(first_seg(cache_lv), 0); /* cache _tdata */
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "cache")))
|
||||
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_CACHE)))
|
||||
return_NULL;
|
||||
|
||||
if (!insert_layer_for_lv(cmd, cache_lv, CACHE, "_corig"))
|
||||
@@ -390,7 +407,7 @@ int lv_cache_remove(struct logical_volume *cache_lv)
|
||||
|
||||
/* Replace 'error' with 'cache' segtype */
|
||||
cache_seg = first_seg(corigin_lv);
|
||||
if (!(cache_seg->segtype = get_segtype_from_string(corigin_lv->vg->cmd, "cache")))
|
||||
if (!(cache_seg->segtype = get_segtype_from_string(corigin_lv->vg->cmd, SEG_TYPE_NAME_CACHE)))
|
||||
return_0;
|
||||
|
||||
if (!(cache_seg->areas = dm_pool_zalloc(cache_lv->vg->vgmem, sizeof(*cache_seg->areas))))
|
||||
@@ -436,7 +453,7 @@ int lv_is_cache_origin(const struct logical_volume *lv)
|
||||
|
||||
static const char *_get_default_cache_policy(struct cmd_context *cmd)
|
||||
{
|
||||
const struct segment_type *segtype = get_segtype_from_string(cmd, "cache");
|
||||
const struct segment_type *segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_CACHE);
|
||||
unsigned attr = ~0;
|
||||
const char *def = NULL;
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ static struct utsname _utsname;
|
||||
static int _utsinit = 0;
|
||||
|
||||
static char *_format_pvsegs(struct dm_pool *mem, const struct lv_segment *seg,
|
||||
int range_format)
|
||||
int range_format, int metadata_areas_only)
|
||||
{
|
||||
unsigned int s;
|
||||
const char *name = NULL;
|
||||
@@ -41,13 +41,19 @@ static char *_format_pvsegs(struct dm_pool *mem, const struct lv_segment *seg,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (metadata_areas_only && (!seg_is_raid(seg) || lv_is_raid_metadata(seg->lv) || lv_is_raid_image(seg->lv)))
|
||||
goto out;
|
||||
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
switch (seg_type(seg, s)) {
|
||||
switch (metadata_areas_only ? seg_metatype(seg, s) : seg_type(seg, s)) {
|
||||
case AREA_LV:
|
||||
name = seg_lv(seg, s)->name;
|
||||
extent = seg_le(seg, s);
|
||||
name = metadata_areas_only ? seg_metalv(seg, s)->name : seg_lv(seg, s)->name;
|
||||
extent = metadata_areas_only ? seg_le(seg, s) : 0;
|
||||
break;
|
||||
case AREA_PV:
|
||||
/* Raid metadata never uses PVs directly */
|
||||
if (metadata_areas_only)
|
||||
continue;
|
||||
name = dev_name(seg_dev(seg, s));
|
||||
extent = seg_pe(seg, s);
|
||||
break;
|
||||
@@ -79,7 +85,7 @@ static char *_format_pvsegs(struct dm_pool *mem, const struct lv_segment *seg,
|
||||
|
||||
if (range_format) {
|
||||
if (dm_snprintf(extent_str, sizeof(extent_str),
|
||||
FMTu32, extent + seg->area_len - 1) < 0) {
|
||||
FMTu32, metadata_areas_only ? extent + seg_metalv(seg, s)->le_count - 1 : extent + seg->area_len - 1) < 0) {
|
||||
log_error("Extent number dm_snprintf failed");
|
||||
return NULL;
|
||||
}
|
||||
@@ -96,6 +102,7 @@ static char *_format_pvsegs(struct dm_pool *mem, const struct lv_segment *seg,
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (!dm_pool_grow_object(mem, "\0", 1)) {
|
||||
log_error("dm_pool_grow_object failed");
|
||||
return NULL;
|
||||
@@ -106,12 +113,22 @@ static char *_format_pvsegs(struct dm_pool *mem, const struct lv_segment *seg,
|
||||
|
||||
char *lvseg_devices(struct dm_pool *mem, const struct lv_segment *seg)
|
||||
{
|
||||
return _format_pvsegs(mem, seg, 0);
|
||||
return _format_pvsegs(mem, seg, 0, 0);
|
||||
}
|
||||
|
||||
char *lvseg_metadata_devices(struct dm_pool *mem, const struct lv_segment *seg)
|
||||
{
|
||||
return _format_pvsegs(mem, seg, 0, 1);
|
||||
}
|
||||
|
||||
char *lvseg_seg_pe_ranges(struct dm_pool *mem, const struct lv_segment *seg)
|
||||
{
|
||||
return _format_pvsegs(mem, seg, 1);
|
||||
return _format_pvsegs(mem, seg, 1, 0);
|
||||
}
|
||||
|
||||
char *lvseg_seg_metadata_le_ranges(struct dm_pool *mem, const struct lv_segment *seg)
|
||||
{
|
||||
return _format_pvsegs(mem, seg, 1, 1);
|
||||
}
|
||||
|
||||
char *lvseg_tags_dup(const struct lv_segment *seg)
|
||||
@@ -219,21 +236,37 @@ uint32_t lv_kernel_read_ahead(const struct logical_volume *lv)
|
||||
return info.read_ahead;
|
||||
}
|
||||
|
||||
static char *_do_lv_origin_dup(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
int uuid)
|
||||
{
|
||||
struct logical_volume *origin;
|
||||
|
||||
|
||||
if (lv_is_cow(lv))
|
||||
origin = origin_from_cow(lv);
|
||||
else if (lv_is_cache(lv) && first_seg(lv)->origin)
|
||||
origin = first_seg(lv)->origin;
|
||||
else if (lv_is_thin_volume(lv) && first_seg(lv)->origin)
|
||||
origin = first_seg(lv)->origin;
|
||||
else if (lv_is_thin_volume(lv) && first_seg(lv)->external_lv)
|
||||
origin = first_seg(lv)->external_lv;
|
||||
else
|
||||
return NULL;
|
||||
|
||||
if (uuid)
|
||||
return lv_uuid_dup(mem, origin);
|
||||
else
|
||||
return lv_name_dup(mem, origin);
|
||||
}
|
||||
|
||||
char *lv_origin_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
if (lv_is_cow(lv))
|
||||
return lv_name_dup(mem, origin_from_cow(lv));
|
||||
return _do_lv_origin_dup(mem, lv, 0);
|
||||
}
|
||||
|
||||
if (lv_is_cache(lv) && first_seg(lv)->origin)
|
||||
return lv_name_dup(mem, first_seg(lv)->origin);
|
||||
|
||||
if (lv_is_thin_volume(lv) && first_seg(lv)->origin)
|
||||
return lv_name_dup(mem, first_seg(lv)->origin);
|
||||
|
||||
if (lv_is_thin_volume(lv) && first_seg(lv)->external_lv)
|
||||
return lv_name_dup(mem, first_seg(lv)->external_lv);
|
||||
|
||||
return NULL;
|
||||
char *lv_origin_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
return _do_lv_origin_dup(mem, lv, 1);
|
||||
}
|
||||
|
||||
char *lv_name_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
@@ -292,43 +325,112 @@ char *lv_modules_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
return tags_format_and_copy(mem, modules);
|
||||
}
|
||||
|
||||
char *lv_mirror_log_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
static char *_do_lv_mirror_log_dup(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
int uuid)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
|
||||
dm_list_iterate_items(seg, &lv->segments)
|
||||
if (seg_is_mirrored(seg) && seg->log_lv)
|
||||
return dm_pool_strdup(mem, seg->log_lv->name);
|
||||
dm_list_iterate_items(seg, &lv->segments) {
|
||||
if (seg_is_mirrored(seg) && seg->log_lv) {
|
||||
if (uuid)
|
||||
return lv_uuid_dup(mem, seg->log_lv);
|
||||
else
|
||||
return lv_name_dup(mem, seg->log_lv);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *lv_mirror_log_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
return _do_lv_mirror_log_dup(mem, lv, 0);
|
||||
}
|
||||
|
||||
char *lv_mirror_log_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
return _do_lv_mirror_log_dup(mem, lv, 1);
|
||||
}
|
||||
|
||||
static char *_do_lv_pool_lv_dup(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
int uuid)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
|
||||
dm_list_iterate_items(seg, &lv->segments) {
|
||||
if (seg->pool_lv &&
|
||||
(seg_is_thin_volume(seg) || seg_is_cache(seg))) {
|
||||
if (uuid)
|
||||
return lv_uuid_dup(mem, seg->pool_lv);
|
||||
else
|
||||
return lv_name_dup(mem, seg->pool_lv);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *lv_pool_lv_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
return _do_lv_pool_lv_dup(mem, lv, 0);
|
||||
}
|
||||
|
||||
dm_list_iterate_items(seg, &lv->segments)
|
||||
if (seg->pool_lv &&
|
||||
(seg_is_thin_volume(seg) || seg_is_cache(seg)))
|
||||
return dm_pool_strdup(mem, seg->pool_lv->name);
|
||||
char *lv_pool_lv_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
return _do_lv_pool_lv_dup(mem, lv, 1);
|
||||
}
|
||||
|
||||
static char *_do_lv_data_lv_dup(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
int uuid)
|
||||
{
|
||||
struct lv_segment *seg = (lv_is_thin_pool(lv) || lv_is_cache_pool(lv)) ?
|
||||
first_seg(lv) : NULL;
|
||||
|
||||
if (seg) {
|
||||
if (uuid)
|
||||
return lv_uuid_dup(mem, seg_lv(seg, 0));
|
||||
else
|
||||
return lv_name_dup(mem, seg_lv(seg, 0));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *lv_data_lv_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
struct lv_segment *seg = (lv_is_thin_pool(lv) || lv_is_cache_pool(lv)) ?
|
||||
first_seg(lv) : NULL;
|
||||
|
||||
return seg ? dm_pool_strdup(mem, seg_lv(seg, 0)->name) : NULL;
|
||||
return _do_lv_data_lv_dup(mem, lv, 0);
|
||||
}
|
||||
|
||||
char *lv_metadata_lv_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
char *lv_data_lv_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
return _do_lv_data_lv_dup(mem, lv, 1);
|
||||
}
|
||||
|
||||
|
||||
static char *_do_lv_metadata_lv_dup(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
int uuid)
|
||||
{
|
||||
struct lv_segment *seg = (lv_is_thin_pool(lv) || lv_is_cache_pool(lv)) ?
|
||||
first_seg(lv) : NULL;
|
||||
|
||||
return seg ? dm_pool_strdup(mem, seg->metadata_lv->name) : NULL;
|
||||
if (seg) {
|
||||
if (uuid)
|
||||
return lv_uuid_dup(mem, seg->metadata_lv);
|
||||
else
|
||||
return lv_name_dup(mem, seg->metadata_lv);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *lv_metadata_lv_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
return _do_lv_metadata_lv_dup(mem, lv, 0);
|
||||
}
|
||||
|
||||
char *lv_metadata_lv_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
return _do_lv_metadata_lv_dup(mem, lv, 1);
|
||||
}
|
||||
|
||||
const char *lv_layer(const struct logical_volume *lv)
|
||||
@@ -358,7 +460,8 @@ int lv_kernel_major(const struct logical_volume *lv)
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *lv_convert_lv_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
static char *_do_lv_convert_lv_dup(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
int uuid)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
|
||||
@@ -367,17 +470,32 @@ char *lv_convert_lv_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
|
||||
/* Temporary mirror is always area_num == 0 */
|
||||
if (seg_type(seg, 0) == AREA_LV &&
|
||||
is_temporary_mirror_layer(seg_lv(seg, 0)))
|
||||
return dm_pool_strdup(mem, seg_lv(seg, 0)->name);
|
||||
is_temporary_mirror_layer(seg_lv(seg, 0))) {
|
||||
if (uuid)
|
||||
return lv_uuid_dup(mem, seg_lv(seg, 0));
|
||||
else
|
||||
return lv_name_dup(mem, seg_lv(seg, 0));
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *lv_move_pv_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
char *lv_convert_lv_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
return _do_lv_convert_lv_dup(mem, lv, 0);
|
||||
}
|
||||
|
||||
char *lv_convert_lv_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
return _do_lv_convert_lv_dup(mem, lv, 1);
|
||||
}
|
||||
|
||||
static char *_do_lv_move_pv_dup(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
int uuid)
|
||||
{
|
||||
struct logical_volume *mimage0_lv;
|
||||
struct lv_segment *seg;
|
||||
const struct device *dev;
|
||||
struct pv_segment *pvseg;
|
||||
|
||||
dm_list_iterate_items(seg, &lv->segments) {
|
||||
if (seg->status & PVMOVE) {
|
||||
@@ -388,17 +506,30 @@ char *lv_move_pv_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
"Bad pvmove structure");
|
||||
return NULL;
|
||||
}
|
||||
dev = seg_dev(first_seg(mimage0_lv), 0);
|
||||
pvseg = seg_pvseg(first_seg(mimage0_lv), 0);
|
||||
} else /* Segment pvmove */
|
||||
dev = seg_dev(seg, 0);
|
||||
pvseg = seg_pvseg(seg, 0);
|
||||
|
||||
return dm_pool_strdup(mem, dev_name(dev));
|
||||
if (uuid)
|
||||
return pv_uuid_dup(mem, pvseg->pv);
|
||||
else
|
||||
return pv_name_dup(mem, pvseg->pv);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *lv_move_pv_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
return _do_lv_move_pv_dup(mem, lv, 0);
|
||||
}
|
||||
|
||||
char *lv_move_pv_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
return _do_lv_move_pv_dup(mem, lv, 1);
|
||||
}
|
||||
|
||||
uint64_t lv_origin_size(const struct logical_volume *lv)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
@@ -479,9 +610,9 @@ char *lv_dmpath_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
return repstr;
|
||||
}
|
||||
|
||||
char *lv_uuid_dup(const struct logical_volume *lv)
|
||||
char *lv_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
return id_format_and_copy(lv->vg->vgmem, &lv->lvid.id[1]);
|
||||
return id_format_and_copy(mem ? mem : lv->vg->vgmem, &lv->lvid.id[1]);
|
||||
}
|
||||
|
||||
char *lv_tags_dup(const struct logical_volume *lv)
|
||||
@@ -534,6 +665,7 @@ int lv_raid_image_in_sync(const struct logical_volume *lv)
|
||||
|
||||
if ((seg = first_seg(lv)))
|
||||
raid_seg = get_only_segment_using_this_lv(seg->lv);
|
||||
|
||||
if (!raid_seg) {
|
||||
log_error("Failed to find RAID segment for %s", lv->name);
|
||||
return 0;
|
||||
|
||||
@@ -35,8 +35,8 @@ struct logical_volume {
|
||||
int32_t major;
|
||||
int32_t minor;
|
||||
|
||||
uint64_t size; /* Sectors */
|
||||
uint32_t le_count;
|
||||
uint64_t size; /* Sectors visible */
|
||||
uint32_t le_count; /* Logical extents visible */
|
||||
|
||||
uint32_t origin_count;
|
||||
uint32_t external_count;
|
||||
@@ -62,25 +62,34 @@ uint64_t lv_size(const struct logical_volume *lv);
|
||||
uint64_t lv_metadata_size(const struct logical_volume *lv);
|
||||
char *lv_attr_dup_with_info_and_seg_status(struct dm_pool *mem, const struct lv_with_info_and_seg_status *lvdm);
|
||||
char *lv_attr_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_uuid_dup(const struct logical_volume *lv);
|
||||
char *lv_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_tags_dup(const struct logical_volume *lv);
|
||||
char *lv_path_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_dmpath_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
uint64_t lv_origin_size(const struct logical_volume *lv);
|
||||
char *lv_move_pv_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_move_pv_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_convert_lv_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_convert_lv_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
int lv_kernel_major(const struct logical_volume *lv);
|
||||
int lv_kernel_minor(const struct logical_volume *lv);
|
||||
char *lv_mirror_log_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_mirror_log_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_data_lv_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_data_lv_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_metadata_lv_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_metadata_lv_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_pool_lv_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_pool_lv_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
|
||||
char *lv_modules_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_name_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_fullname_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
struct logical_volume *lv_parent(const struct logical_volume *lv);
|
||||
char *lv_parent_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_origin_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_origin_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
|
||||
uint32_t lv_kernel_read_ahead(const struct logical_volume *lv);
|
||||
const char *lvseg_name(const struct lv_segment *seg);
|
||||
uint64_t lvseg_start(const struct lv_segment *seg);
|
||||
@@ -92,7 +101,9 @@ char *lvseg_cachemode_dup(struct dm_pool *mem, const struct lv_segment *seg);
|
||||
char *lvseg_monitor_dup(struct dm_pool *mem, const struct lv_segment *seg);
|
||||
char *lvseg_tags_dup(const struct lv_segment *seg);
|
||||
char *lvseg_devices(struct dm_pool *mem, const struct lv_segment *seg);
|
||||
char *lvseg_metadata_devices(struct dm_pool *mem, const struct lv_segment *seg);
|
||||
char *lvseg_seg_pe_ranges(struct dm_pool *mem, const struct lv_segment *seg);
|
||||
char *lvseg_seg_metadata_le_ranges(struct dm_pool *mem, const struct lv_segment *seg);
|
||||
char *lv_time_dup(struct dm_pool *mem, const struct logical_volume *lv, int iso_mode);
|
||||
char *lv_host_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
int lv_set_creation(struct logical_volume *lv,
|
||||
|
||||
@@ -129,6 +129,8 @@ enum {
|
||||
LV_TYPE_RAID6_ZR,
|
||||
LV_TYPE_RAID6_NR,
|
||||
LV_TYPE_RAID6_NC,
|
||||
LV_TYPE_LOCKD,
|
||||
LV_TYPE_SANLOCK
|
||||
};
|
||||
|
||||
static const char *_lv_type_names[] = {
|
||||
@@ -173,6 +175,8 @@ static const char *_lv_type_names[] = {
|
||||
[LV_TYPE_RAID6_ZR] = SEG_TYPE_NAME_RAID6_ZR,
|
||||
[LV_TYPE_RAID6_NR] = SEG_TYPE_NAME_RAID6_NR,
|
||||
[LV_TYPE_RAID6_NC] = SEG_TYPE_NAME_RAID6_NC,
|
||||
[LV_TYPE_LOCKD] = "lockd",
|
||||
[LV_TYPE_SANLOCK] = "sanlock",
|
||||
};
|
||||
|
||||
static int _lv_layout_and_role_mirror(struct dm_pool *mem,
|
||||
@@ -224,7 +228,7 @@ static int _lv_layout_and_role_raid(struct dm_pool *mem,
|
||||
int *public_lv)
|
||||
{
|
||||
int top_level = 0;
|
||||
const char *seg_name;
|
||||
const struct segment_type *segtype;
|
||||
|
||||
/* non-top-level LVs */
|
||||
if (lv_is_raid_image(lv)) {
|
||||
@@ -251,43 +255,45 @@ static int _lv_layout_and_role_raid(struct dm_pool *mem,
|
||||
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID]))
|
||||
goto_bad;
|
||||
|
||||
if (!strcmp(first_seg(lv)->segtype->name, SEG_TYPE_NAME_RAID1)) {
|
||||
segtype = first_seg(lv)->segtype;
|
||||
|
||||
if (segtype_is_raid1(segtype)) {
|
||||
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID1]))
|
||||
goto_bad;
|
||||
} else if (!strcmp(first_seg(lv)->segtype->name, SEG_TYPE_NAME_RAID10)) {
|
||||
} else if (segtype_is_raid10(segtype)) {
|
||||
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID10]))
|
||||
goto_bad;
|
||||
} else if (!strcmp(first_seg(lv)->segtype->name, SEG_TYPE_NAME_RAID4)) {
|
||||
} else if (segtype_is_raid4(segtype)) {
|
||||
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID4]))
|
||||
goto_bad;
|
||||
} else if (!strncmp(seg_name = first_seg(lv)->segtype->name, SEG_TYPE_NAME_RAID5, strlen(SEG_TYPE_NAME_RAID5))) {
|
||||
} else if (segtype_is_any_raid5(segtype)) {
|
||||
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID5]))
|
||||
goto_bad;
|
||||
|
||||
if (!strcmp(seg_name, SEG_TYPE_NAME_RAID5_LA)) {
|
||||
if (segtype_is_raid5_la(segtype)) {
|
||||
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID5_LA]))
|
||||
goto_bad;
|
||||
} else if (!strcmp(seg_name, SEG_TYPE_NAME_RAID5_RA)) {
|
||||
} else if (segtype_is_raid5_ra(segtype)) {
|
||||
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID5_RA]))
|
||||
goto_bad;
|
||||
} else if (!strcmp(seg_name, SEG_TYPE_NAME_RAID5_LS)) {
|
||||
} else if (segtype_is_raid5_ls(segtype)) {
|
||||
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID5_LS]))
|
||||
goto_bad;
|
||||
} else if (!strcmp(seg_name, SEG_TYPE_NAME_RAID5_RS)) {
|
||||
} else if (segtype_is_raid5_rs(segtype)) {
|
||||
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID5_RS]))
|
||||
goto_bad;
|
||||
}
|
||||
} else if (!strncmp(seg_name = first_seg(lv)->segtype->name, SEG_TYPE_NAME_RAID6, strlen(SEG_TYPE_NAME_RAID6))) {
|
||||
} else if (segtype_is_any_raid6(segtype)) {
|
||||
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID6]))
|
||||
goto_bad;
|
||||
|
||||
if (!strcmp(seg_name, SEG_TYPE_NAME_RAID6_ZR)) {
|
||||
if (segtype_is_raid6_zr(segtype)) {
|
||||
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID6_ZR]))
|
||||
goto_bad;
|
||||
} else if (!strcmp(seg_name, SEG_TYPE_NAME_RAID6_NR)) {
|
||||
} else if (segtype_is_raid6_nr(segtype)) {
|
||||
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID6_NR]))
|
||||
goto_bad;
|
||||
} else if (!strcmp(seg_name, SEG_TYPE_NAME_RAID6_NC)) {
|
||||
} else if (segtype_is_raid6_nc(segtype)) {
|
||||
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID6_NC]))
|
||||
goto_bad;
|
||||
}
|
||||
@@ -503,6 +509,13 @@ int lv_layout_and_role(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
if (!_lv_layout_and_role_thick_origin_snapshot(mem, lv, *layout, *role, &public_lv))
|
||||
goto_bad;
|
||||
|
||||
if (lv_is_lockd_sanlock_lv(lv)) {
|
||||
if (!str_list_add_no_dup_check(mem, *role, _lv_type_names[LV_TYPE_LOCKD]) ||
|
||||
!str_list_add_no_dup_check(mem, *role, _lv_type_names[LV_TYPE_SANLOCK]))
|
||||
goto_bad;
|
||||
public_lv = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If layout not yet determined, it must be either
|
||||
* linear or striped or mixture of these two.
|
||||
@@ -778,7 +791,7 @@ int get_default_region_size(struct cmd_context *cmd)
|
||||
|
||||
if (region_size & (region_size - 1)) {
|
||||
region_size = _round_down_pow2(region_size);
|
||||
log_verbose("Reducing mirror region size to %u kiB (power of 2).",
|
||||
log_verbose("Reducing region size to %u kiB (power of 2).",
|
||||
region_size / 2);
|
||||
}
|
||||
|
||||
@@ -928,7 +941,7 @@ dm_percent_t copy_percent(const struct logical_volume *lv)
|
||||
dm_list_iterate_items(seg, &lv->segments) {
|
||||
denominator += seg->area_len;
|
||||
|
||||
/* FIXME Generalise name of 'extents_copied' field */
|
||||
/* FIXME Generalise name of 'extents_copied' field */
|
||||
if ((seg_is_raid(seg) || seg_is_mirrored(seg)) &&
|
||||
(seg->area_count > 1))
|
||||
numerator += seg->extents_copied;
|
||||
@@ -936,7 +949,27 @@ dm_percent_t copy_percent(const struct logical_volume *lv)
|
||||
numerator += seg->area_len;
|
||||
}
|
||||
|
||||
return denominator ? dm_make_percent( numerator, denominator ) : 100.0;
|
||||
return denominator ? dm_make_percent(numerator, denominator) : 100.0;
|
||||
}
|
||||
|
||||
/* Round up extents to next stripe boundary for number of stripes */
|
||||
static uint32_t _round_to_stripe_boundary(struct volume_group *vg, uint32_t extents,
|
||||
uint32_t stripes, int extend)
|
||||
{
|
||||
uint32_t size_rest, new_extents = extents;
|
||||
|
||||
if (!stripes)
|
||||
return extents;
|
||||
|
||||
/* Round up extents to stripe divisible amount */
|
||||
if ((size_rest = extents % stripes)) {
|
||||
new_extents += extend ? stripes - size_rest : -size_rest;
|
||||
log_print_unless_silent("Rounding size %s (%d extents) up to stripe boundary size %s (%d extents).",
|
||||
display_size(vg->cmd, extents * vg->extent_size), extents,
|
||||
display_size(vg->cmd, new_extents * vg->extent_size), new_extents);
|
||||
}
|
||||
|
||||
return new_extents;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1011,7 +1044,7 @@ struct lv_segment *alloc_snapshot_seg(struct logical_volume *lv,
|
||||
struct lv_segment *seg;
|
||||
const struct segment_type *segtype;
|
||||
|
||||
segtype = get_segtype_from_string(lv->vg->cmd, "snapshot");
|
||||
segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_SNAPSHOT);
|
||||
if (!segtype) {
|
||||
log_error("Failed to find snapshot segtype");
|
||||
return NULL;
|
||||
@@ -1035,6 +1068,7 @@ static int _release_and_discard_lv_segment_area(struct lv_segment *seg, uint32_t
|
||||
uint32_t area_reduction, int with_discard)
|
||||
{
|
||||
struct lv_segment *cache_seg;
|
||||
struct logical_volume *lv = seg_lv(seg, s);
|
||||
|
||||
if (seg_type(seg, s) == AREA_UNASSIGNED)
|
||||
return 1;
|
||||
@@ -1052,10 +1086,10 @@ static int _release_and_discard_lv_segment_area(struct lv_segment *seg, uint32_t
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (lv_is_mirror_image(seg_lv(seg, s)) ||
|
||||
lv_is_thin_pool_data(seg_lv(seg, s)) ||
|
||||
lv_is_cache_pool_data(seg_lv(seg, s))) {
|
||||
if (!lv_reduce(seg_lv(seg, s), area_reduction))
|
||||
if (lv_is_mirror_image(lv) ||
|
||||
lv_is_thin_pool_data(lv) ||
|
||||
lv_is_cache_pool_data(lv)) {
|
||||
if (!lv_reduce(lv, area_reduction))
|
||||
return_0; /* FIXME: any upper level reporting */
|
||||
return 1;
|
||||
}
|
||||
@@ -1069,20 +1103,20 @@ static int _release_and_discard_lv_segment_area(struct lv_segment *seg, uint32_t
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (lv_is_raid_image(seg_lv(seg, s))) {
|
||||
if (lv_is_raid_image(lv)) {
|
||||
/*
|
||||
* FIXME: Use lv_reduce not lv_remove
|
||||
* We use lv_remove for now, because I haven't figured out
|
||||
* why lv_reduce won't remove the LV.
|
||||
lv_reduce(seg_lv(seg, s), area_reduction);
|
||||
lv_reduce(lv, area_reduction);
|
||||
*/
|
||||
if (area_reduction != seg->area_len) {
|
||||
log_error("Unable to reduce RAID LV - operation not implemented.");
|
||||
return_0;
|
||||
} else {
|
||||
if (!lv_remove(seg_lv(seg, s))) {
|
||||
if (!lv_remove(lv)) {
|
||||
log_error("Failed to remove RAID image %s",
|
||||
seg_lv(seg, s)->name);
|
||||
lv->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1103,9 +1137,9 @@ static int _release_and_discard_lv_segment_area(struct lv_segment *seg, uint32_t
|
||||
log_very_verbose("Remove %s:%" PRIu32 "[%" PRIu32 "] from "
|
||||
"the top of LV %s:%" PRIu32,
|
||||
seg->lv->name, seg->le, s,
|
||||
seg_lv(seg, s)->name, seg_le(seg, s));
|
||||
lv->name, seg_le(seg, s));
|
||||
|
||||
if (!remove_seg_from_segs_using_this_lv(seg_lv(seg, s), seg))
|
||||
if (!remove_seg_from_segs_using_this_lv(lv, seg))
|
||||
return_0;
|
||||
seg_lv(seg, s) = NULL;
|
||||
seg_le(seg, s) = 0;
|
||||
@@ -1241,6 +1275,51 @@ static int _lv_segment_add_areas(struct logical_volume *lv,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint32_t _calc_area_multiple(const struct segment_type *segtype,
|
||||
const uint32_t area_count,
|
||||
const uint32_t stripes)
|
||||
{
|
||||
if (!area_count)
|
||||
return 1;
|
||||
|
||||
/* Striped */
|
||||
if (segtype_is_striped(segtype))
|
||||
return area_count;
|
||||
|
||||
/* Parity RAID (e.g. RAID 4/5/6) */
|
||||
if (segtype_is_raid(segtype) && segtype->parity_devs) {
|
||||
/*
|
||||
* As articulated in _alloc_init, we can tell by
|
||||
* the area_count whether a replacement drive is
|
||||
* being allocated; and if this is the case, then
|
||||
* there is no area_multiple that should be used.
|
||||
*/
|
||||
if (area_count <= segtype->parity_devs)
|
||||
return 1;
|
||||
|
||||
return area_count - segtype->parity_devs;
|
||||
}
|
||||
|
||||
/*
|
||||
* RAID10 - only has 2-way mirror right now.
|
||||
* If we are to move beyond 2-way RAID10, then
|
||||
* the 'stripes' argument will always need to
|
||||
* be given.
|
||||
*/
|
||||
if (!strcmp(segtype->name, _lv_type_names[LV_TYPE_RAID10])) {
|
||||
if (!stripes)
|
||||
return area_count / 2;
|
||||
return stripes;
|
||||
}
|
||||
|
||||
/* Mirrored stripes */
|
||||
if (stripes)
|
||||
return stripes;
|
||||
|
||||
/* Mirrored */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reduce the size of an lv_segment. New size can be zero.
|
||||
*/
|
||||
@@ -1391,7 +1470,7 @@ int replace_lv_with_error_segment(struct logical_volume *lv)
|
||||
|
||||
/* FIXME Check for any attached LVs that will become orphans e.g. mirror logs */
|
||||
|
||||
if (!lv_add_virtual_segment(lv, 0, len, get_segtype_from_string(lv->vg->cmd, "error")))
|
||||
if (!lv_add_virtual_segment(lv, 0, len, get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_ERROR)))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
@@ -1458,10 +1537,10 @@ struct alloc_handle {
|
||||
struct dm_pool *mem;
|
||||
|
||||
alloc_policy_t alloc; /* Overall policy */
|
||||
int approx_alloc; /* get as much as possible up to new_extents */
|
||||
int approx_alloc; /* get as much as possible up to new_extents */
|
||||
uint32_t new_extents; /* Number of new extents required */
|
||||
uint32_t area_count; /* Number of parallel areas */
|
||||
uint32_t parity_count; /* Adds to area_count, but not area_multiple */
|
||||
uint32_t parity_count; /* Adds to area_count, but not area_multiple */
|
||||
uint32_t area_multiple; /* seg->len = area_len * area_multiple */
|
||||
uint32_t log_area_count; /* Number of parallel logs */
|
||||
uint32_t metadata_area_count; /* Number of parallel metadata areas */
|
||||
@@ -1496,50 +1575,6 @@ struct alloc_handle {
|
||||
struct dm_list alloced_areas[0];
|
||||
};
|
||||
|
||||
static uint32_t _calc_area_multiple(const struct segment_type *segtype,
|
||||
const uint32_t area_count,
|
||||
const uint32_t stripes)
|
||||
{
|
||||
if (!area_count)
|
||||
return 1;
|
||||
|
||||
/* Striped */
|
||||
if (segtype_is_striped(segtype))
|
||||
return area_count;
|
||||
|
||||
/* Parity RAID (e.g. RAID 4/5/6) */
|
||||
if (segtype_is_raid(segtype) && segtype->parity_devs) {
|
||||
/*
|
||||
* As articulated in _alloc_init, we can tell by
|
||||
* the area_count whether a replacement drive is
|
||||
* being allocated; and if this is the case, then
|
||||
* there is no area_multiple that should be used.
|
||||
*/
|
||||
if (area_count <= segtype->parity_devs)
|
||||
return 1;
|
||||
return area_count - segtype->parity_devs;
|
||||
}
|
||||
|
||||
/*
|
||||
* RAID10 - only has 2-way mirror right now.
|
||||
* If we are to move beyond 2-way RAID10, then
|
||||
* the 'stripes' argument will always need to
|
||||
* be given.
|
||||
*/
|
||||
if (!strcmp(segtype->name, _lv_type_names[LV_TYPE_RAID10])) {
|
||||
if (!stripes)
|
||||
return area_count / 2;
|
||||
return stripes;
|
||||
}
|
||||
|
||||
/* Mirrored stripes */
|
||||
if (stripes)
|
||||
return stripes;
|
||||
|
||||
/* Mirrored */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns log device size in extents, algorithm from kernel code
|
||||
*/
|
||||
@@ -1581,7 +1616,7 @@ static int _sufficient_pes_free(struct alloc_handle *ah, struct dm_list *pvms,
|
||||
{
|
||||
uint32_t area_extents_needed = (extents_still_needed - allocated) * ah->area_count / ah->area_multiple;
|
||||
uint32_t parity_extents_needed = (extents_still_needed - allocated) * ah->parity_count / ah->area_multiple;
|
||||
uint32_t metadata_extents_needed = (ah->alloc_and_split_meta) ? 0 : ah->metadata_area_count * RAID_METADATA_AREA_LEN; /* One each */
|
||||
uint32_t metadata_extents_needed = ah->alloc_and_split_meta ? 0 : ah->metadata_area_count * RAID_METADATA_AREA_LEN; /* One each */
|
||||
uint32_t total_extents_needed = area_extents_needed + parity_extents_needed + metadata_extents_needed;
|
||||
uint32_t free_pes = pv_maps_size(pvms);
|
||||
|
||||
@@ -1724,9 +1759,9 @@ static int _setup_alloced_segment(struct logical_volume *lv, uint64_t status,
|
||||
struct lv_segment *seg;
|
||||
|
||||
area_multiple = _calc_area_multiple(segtype, area_count, 0);
|
||||
extents = aa[0].len * area_multiple;
|
||||
|
||||
if (!(seg = alloc_lv_segment(segtype, lv, lv->le_count,
|
||||
aa[0].len * area_multiple,
|
||||
if (!(seg = alloc_lv_segment(segtype, lv, lv->le_count, extents,
|
||||
status, stripe_size, NULL,
|
||||
area_count,
|
||||
aa[0].len, 0u, region_size, 0u, NULL))) {
|
||||
@@ -1742,7 +1777,7 @@ static int _setup_alloced_segment(struct logical_volume *lv, uint64_t status,
|
||||
|
||||
extents = aa[0].len * area_multiple;
|
||||
lv->le_count += extents;
|
||||
lv->size += (uint64_t) extents *lv->vg->extent_size;
|
||||
lv->size += (uint64_t) extents * lv->vg->extent_size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1908,7 +1943,7 @@ static int _for_each_pv(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
*max_seg_len = remaining_seg_len;
|
||||
|
||||
area_multiple = _calc_area_multiple(seg->segtype, seg->area_count, 0);
|
||||
area_len = remaining_seg_len / area_multiple ? : 1;
|
||||
area_len = (remaining_seg_len / area_multiple) ? : 1;
|
||||
|
||||
/* For striped mirrors, all the areas are counted, through the mirror layer */
|
||||
if (top_level_area_index == -1)
|
||||
@@ -2954,7 +2989,7 @@ static int _allocate(struct alloc_handle *ah,
|
||||
|
||||
if (ah->area_multiple > 1 &&
|
||||
(ah->new_extents - alloc_state.allocated) % ah->area_multiple) {
|
||||
log_error("Number of extents requested (%d) needs to be divisible by %d.",
|
||||
log_error("Number of extents requested (" FMTu32 ") needs to be divisible by " FMTu32 ".",
|
||||
ah->new_extents - alloc_state.allocated,
|
||||
ah->area_multiple);
|
||||
return 0;
|
||||
@@ -3399,7 +3434,7 @@ static struct lv_segment *_convert_seg_to_mirror(struct lv_segment *seg,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(newseg = alloc_lv_segment(get_segtype_from_string(seg->lv->vg->cmd, "mirror"),
|
||||
if (!(newseg = alloc_lv_segment(get_segtype_from_string(seg->lv->vg->cmd, SEG_TYPE_NAME_MIRROR),
|
||||
seg->lv, seg->le, seg->len,
|
||||
seg->status, seg->stripe_size,
|
||||
log_lv,
|
||||
@@ -3492,7 +3527,7 @@ int lv_add_segmented_mirror_image(struct alloc_handle *ah,
|
||||
if (!lv_add_mirror_lvs(lv, ©_lv, 1, MIRROR_IMAGE, region_size))
|
||||
return_0;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, "striped")))
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
dm_list_iterate_items(aa, &ah->alloced_areas[0]) {
|
||||
@@ -3606,7 +3641,7 @@ int lv_add_mirror_lvs(struct logical_volume *lv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
mirror_segtype = get_segtype_from_string(lv->vg->cmd, "mirror");
|
||||
mirror_segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_MIRROR);
|
||||
if (seg->segtype != mirror_segtype)
|
||||
if (!(seg = _convert_seg_to_mirror(seg, region_size, NULL)))
|
||||
return_0;
|
||||
@@ -3665,8 +3700,7 @@ int lv_add_log_segment(struct alloc_handle *ah, uint32_t first_area,
|
||||
{
|
||||
|
||||
return lv_add_segment(ah, ah->area_count + first_area, 1, log_lv,
|
||||
get_segtype_from_string(log_lv->vg->cmd,
|
||||
"striped"),
|
||||
get_segtype_from_string(log_lv->vg->cmd, SEG_TYPE_NAME_STRIPED),
|
||||
0, status, 0);
|
||||
}
|
||||
|
||||
@@ -3763,23 +3797,23 @@ static int _lv_extend_layered_lv(struct alloc_handle *ah,
|
||||
{
|
||||
const struct segment_type *segtype;
|
||||
struct logical_volume *sub_lv, *meta_lv;
|
||||
struct lv_segment *seg;
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
uint32_t fa, s;
|
||||
int clear_metadata = 0;
|
||||
|
||||
segtype = get_segtype_from_string(lv->vg->cmd, "striped");
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
/*
|
||||
* The component devices of a "striped" LV all go in the same
|
||||
* LV. However, RAID has an LV for each device - making the
|
||||
* 'stripes' and 'stripe_size' parameters meaningless.
|
||||
*/
|
||||
if (seg_is_raid(first_seg(lv))) {
|
||||
if (seg_is_raid(seg)) {
|
||||
stripes = 1;
|
||||
stripe_size = 0;
|
||||
}
|
||||
|
||||
seg = first_seg(lv);
|
||||
for (fa = first_area, s = 0; s < seg->area_count; s++) {
|
||||
if (is_temporary_mirror_layer(seg_lv(seg, s))) {
|
||||
if (!_lv_extend_layered_lv(ah, seg_lv(seg, s), extents,
|
||||
@@ -4390,6 +4424,25 @@ static int _fsadm_cmd(struct cmd_context *cmd,
|
||||
return exec_cmd(cmd, argv, status, 1);
|
||||
}
|
||||
|
||||
static int _adjust_amount(dm_percent_t percent, int policy_threshold, int *policy_amount)
|
||||
{
|
||||
if (!(DM_PERCENT_0 < percent && percent <= DM_PERCENT_100) ||
|
||||
percent <= (policy_threshold * DM_PERCENT_1))
|
||||
return 0;
|
||||
/*
|
||||
* Evaluate the minimal amount needed to get bellow threshold.
|
||||
* Keep using DM_PERCENT_1 units for better precision.
|
||||
* Round-up to needed percentage value
|
||||
*/
|
||||
percent = (percent/policy_threshold + (DM_PERCENT_1 - 1) / 100) / (DM_PERCENT_1 / 100) - 100;
|
||||
|
||||
/* Use it if current policy amount is smaller */
|
||||
if (*policy_amount < percent)
|
||||
*policy_amount = percent;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _adjust_policy_params(struct cmd_context *cmd,
|
||||
struct logical_volume *lv, struct lvresize_params *lp)
|
||||
{
|
||||
@@ -4399,49 +4452,65 @@ static int _adjust_policy_params(struct cmd_context *cmd,
|
||||
if (lv_is_thin_pool(lv)) {
|
||||
policy_threshold =
|
||||
find_config_tree_int(cmd, activation_thin_pool_autoextend_threshold_CFG,
|
||||
lv_config_profile(lv)) * DM_PERCENT_1;
|
||||
lv_config_profile(lv));
|
||||
policy_amount =
|
||||
find_config_tree_int(cmd, activation_thin_pool_autoextend_percent_CFG,
|
||||
lv_config_profile(lv));
|
||||
if (!policy_amount && policy_threshold < DM_PERCENT_100)
|
||||
return 0;
|
||||
if (policy_threshold < 50) {
|
||||
log_warn("WARNING: Thin pool autoextend threshold %d%% is set below "
|
||||
"minimum supported 50%%.", policy_threshold);
|
||||
policy_threshold = 50;
|
||||
}
|
||||
} else {
|
||||
policy_threshold =
|
||||
find_config_tree_int(cmd, activation_snapshot_autoextend_threshold_CFG, NULL) * DM_PERCENT_1;
|
||||
find_config_tree_int(cmd, activation_snapshot_autoextend_threshold_CFG, NULL);
|
||||
policy_amount =
|
||||
find_config_tree_int(cmd, activation_snapshot_autoextend_percent_CFG, NULL);
|
||||
if (policy_threshold < 50) {
|
||||
log_warn("WARNING: Snapshot autoextend threshold %d%% is set bellow "
|
||||
"minimal supported value 50%%.", policy_threshold);
|
||||
policy_threshold = 50;
|
||||
}
|
||||
}
|
||||
|
||||
if (policy_threshold >= DM_PERCENT_100)
|
||||
if (!policy_amount && policy_threshold < 100) {
|
||||
log_error("Can't extend %s with %s autoextend percent set to 0%%.",
|
||||
display_lvname(lv), first_seg(lv)->segtype->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (policy_threshold >= 100)
|
||||
return 1; /* nothing to do */
|
||||
|
||||
if (!lv_is_active_locally(lv)) {
|
||||
log_error("Can't read state of locally inactive LV %s.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lv_is_thin_pool(lv)) {
|
||||
if (!lv_thin_pool_percent(lv, 1, &percent))
|
||||
return_0;
|
||||
if ((DM_PERCENT_0 < percent && percent <= DM_PERCENT_100) &&
|
||||
(percent > policy_threshold)) {
|
||||
if (_adjust_amount(percent, policy_threshold, &policy_amount)) {
|
||||
if (!thin_pool_feature_supported(lv, THIN_FEATURE_METADATA_RESIZE)) {
|
||||
log_error_once("Online metadata resize for %s/%s is not supported.",
|
||||
lv->vg->name, lv->name);
|
||||
log_error_once("Online metadata resize for %s is not supported.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
lp->poolmetadatasize = (first_seg(lv)->metadata_lv->size *
|
||||
policy_amount + 99) / 100;
|
||||
lp->poolmetadatasign = SIGN_PLUS;
|
||||
}
|
||||
|
||||
if (!lv_thin_pool_percent(lv, 0, &percent))
|
||||
return_0;
|
||||
if (!(DM_PERCENT_0 < percent && percent <= DM_PERCENT_100) ||
|
||||
percent <= policy_threshold)
|
||||
return 1;
|
||||
} else {
|
||||
if (!lv_snapshot_percent(lv, &percent))
|
||||
return_0;
|
||||
if (!(DM_PERCENT_0 < percent && percent <= DM_PERCENT_100) || percent <= policy_threshold)
|
||||
return 1; /* nothing to do */
|
||||
}
|
||||
|
||||
if (!_adjust_amount(percent, policy_threshold, &policy_amount))
|
||||
return 1; /* nothing to do */
|
||||
|
||||
lp->extents = policy_amount;
|
||||
lp->sizeargs = (lp->extents) ? 1 : 0;
|
||||
|
||||
@@ -4536,7 +4605,7 @@ static int _lvresize_poolmetadata(struct cmd_context *cmd, struct volume_group *
|
||||
struct dm_list *pvh)
|
||||
{
|
||||
struct logical_volume *lv = first_seg(pool_lv)->metadata_lv;
|
||||
alloc_policy_t alloc = lp->ac_alloc ?: lv->alloc;
|
||||
alloc_policy_t alloc = lp->ac_alloc ? : lv->alloc;
|
||||
struct lv_segment *mseg = last_seg(lv);
|
||||
uint32_t seg_mirrors = lv_mirror_count(lv);
|
||||
|
||||
@@ -5145,7 +5214,7 @@ static struct logical_volume *_lvresize_volume(struct cmd_context *cmd,
|
||||
/* Switch to layered LV resizing */
|
||||
lv = seg_lv(seg, 0);
|
||||
}
|
||||
alloc = lp->ac_alloc ?: lv->alloc;
|
||||
alloc = lp->ac_alloc ? : lv->alloc;
|
||||
|
||||
if ((lp->resize == LV_REDUCE) && lp->argc)
|
||||
log_print_unless_silent("Ignoring PVs on command line when reducing.");
|
||||
@@ -5162,7 +5231,7 @@ static struct logical_volume *_lvresize_volume(struct cmd_context *cmd,
|
||||
log_error("Filesystem check failed.");
|
||||
return NULL;
|
||||
}
|
||||
/* some filesystems supports online resize */
|
||||
/* some filesystems support online resize */
|
||||
}
|
||||
|
||||
/* FIXME forks here */
|
||||
@@ -6198,7 +6267,7 @@ int remove_layers_for_segments(struct cmd_context *cmd,
|
||||
|
||||
/* Replace mirror with error segment */
|
||||
if (!(lseg->segtype =
|
||||
get_segtype_from_string(lv->vg->cmd, "error"))) {
|
||||
get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_ERROR))) {
|
||||
log_error("Missing error segtype");
|
||||
return 0;
|
||||
}
|
||||
@@ -6252,6 +6321,7 @@ int move_lv_segments(struct logical_volume *lv_to,
|
||||
struct logical_volume *lv_from,
|
||||
uint64_t set_status, uint64_t reset_status)
|
||||
{
|
||||
const uint64_t MOVE_BITS = (RAID | MIRROR | THIN_VOLUME);
|
||||
struct lv_segment *seg;
|
||||
|
||||
dm_list_iterate_items(seg, &lv_to->segments)
|
||||
@@ -6269,6 +6339,16 @@ int move_lv_segments(struct logical_volume *lv_to,
|
||||
seg->status |= set_status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Move LV status bits for selected types with their segments
|
||||
* i.e. when inserting layer to cache LV, we move raid segments
|
||||
* to a new place, thus 'raid' LV property now belongs to this LV.
|
||||
*
|
||||
* Bits should match to those which appears after read from disk.
|
||||
*/
|
||||
lv_to->status |= lv_from->status & MOVE_BITS;
|
||||
lv_from->status &= ~MOVE_BITS;
|
||||
|
||||
lv_to->le_count = lv_from->le_count;
|
||||
lv_to->size = lv_from->size;
|
||||
|
||||
@@ -6321,7 +6401,7 @@ int remove_layer_from_lv(struct logical_volume *lv,
|
||||
return_0;
|
||||
|
||||
/* Replace the empty layer with error segment */
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, "error")))
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_ERROR)))
|
||||
return_0;
|
||||
if (!lv_add_virtual_segment(layer_lv, 0, parent_lv->le_count, segtype))
|
||||
return_0;
|
||||
@@ -6385,7 +6465,7 @@ struct logical_volume *insert_layer_for_lv(struct cmd_context *cmd,
|
||||
if (lv_is_active(lv_where) && strstr(name, "_mimagetmp")) {
|
||||
log_very_verbose("Creating transient LV %s for mirror conversion in VG %s.", name, lv_where->vg->name);
|
||||
|
||||
segtype = get_segtype_from_string(cmd, "error");
|
||||
segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_ERROR);
|
||||
|
||||
if (!lv_add_virtual_segment(layer_lv, 0, lv_where->le_count, segtype)) {
|
||||
log_error("Creation of transient LV %s for mirror conversion in VG %s failed.", name, lv_where->vg->name);
|
||||
@@ -6433,7 +6513,7 @@ struct logical_volume *insert_layer_for_lv(struct cmd_context *cmd,
|
||||
if (!move_lv_segments(layer_lv, lv_where, 0, 0))
|
||||
return_NULL;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "striped")))
|
||||
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_NULL;
|
||||
|
||||
/* allocate a new linear segment */
|
||||
@@ -6483,7 +6563,7 @@ static int _extend_layer_lv_for_segment(struct logical_volume *layer_lv,
|
||||
if (seg_type(seg, s) != AREA_PV && seg_type(seg, s) != AREA_LV)
|
||||
return_0;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(layer_lv->vg->cmd, "striped")))
|
||||
if (!(segtype = get_segtype_from_string(layer_lv->vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
/* FIXME Incomplete message? Needs more context */
|
||||
@@ -6756,7 +6836,7 @@ static struct logical_volume *_create_virtual_origin(struct cmd_context *cmd,
|
||||
char vorigin_name[NAME_LEN];
|
||||
struct logical_volume *lv;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "zero"))) {
|
||||
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_ZERO))) {
|
||||
log_error("Zero segment type for virtual origin not found");
|
||||
return NULL;
|
||||
}
|
||||
@@ -6910,7 +6990,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
const char *new_lv_name)
|
||||
{
|
||||
struct cmd_context *cmd = vg->cmd;
|
||||
uint32_t size_rest, size;
|
||||
uint32_t size;
|
||||
uint64_t status = lp->permission | VISIBLE_LV;
|
||||
const struct segment_type *create_segtype = lp->segtype;
|
||||
struct logical_volume *lv, *origin_lv = NULL;
|
||||
@@ -6975,12 +7055,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
lp->stripe_size = vg->extent_size;
|
||||
}
|
||||
|
||||
if ((size_rest = lp->extents % lp->stripes)) {
|
||||
log_print_unless_silent("Rounding size (%d extents) up to stripe boundary "
|
||||
"size (%d extents).", lp->extents,
|
||||
lp->extents - size_rest + lp->stripes);
|
||||
lp->extents = lp->extents - size_rest + lp->stripes;
|
||||
}
|
||||
lp->extents = _round_to_stripe_boundary(vg, lp->extents, lp->stripes, 1);
|
||||
|
||||
if (!lp->extents && !seg_is_thin_volume(lp)) {
|
||||
log_error(INTERNAL_ERROR "Unable to create new logical volume with no extents.");
|
||||
@@ -7038,12 +7113,25 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
}
|
||||
}
|
||||
|
||||
if (seg_is_thin_volume(lp) &&
|
||||
lv_is_new_thin_pool(pool_lv)) {
|
||||
if (seg_is_thin_volume(lp)) {
|
||||
thin_pool_was_active = lv_is_active(pool_lv);
|
||||
if (!check_new_thin_pool(pool_lv))
|
||||
return_NULL;
|
||||
/* New pool is now inactive */
|
||||
if (lv_is_new_thin_pool(pool_lv)) {
|
||||
if (!check_new_thin_pool(pool_lv))
|
||||
return_NULL;
|
||||
/* New pool is now inactive */
|
||||
} else {
|
||||
if (!activate_lv_excl_local(cmd, pool_lv)) {
|
||||
log_error("Aborting. Failed to locally activate thin pool %s.",
|
||||
display_lvname(pool_lv));
|
||||
return 0;
|
||||
}
|
||||
if (!pool_below_threshold(first_seg(pool_lv))) {
|
||||
log_error("Cannot create new thin volume, free space in "
|
||||
"thin pool %s reached threshold.",
|
||||
display_lvname(pool_lv));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (seg_is_cache(lp) &&
|
||||
@@ -7091,7 +7179,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
}
|
||||
/* Create cache origin for cache pool */
|
||||
/* FIXME Eventually support raid/mirrors with -m */
|
||||
if (!(create_segtype = get_segtype_from_string(vg->cmd, "striped")))
|
||||
if (!(create_segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
} else if (seg_is_mirrored(lp) || seg_is_raid(lp)) {
|
||||
if (is_change_activating(lp->activate) && (lp->activate != CHANGE_AEY) &&
|
||||
@@ -7160,8 +7248,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
return NULL;
|
||||
}
|
||||
if (lv_is_cow(origin_lv)) {
|
||||
log_error("Snapshots of snapshots are not "
|
||||
"supported yet.");
|
||||
log_error("Snapshots of snapshots are not supported.");
|
||||
return NULL;
|
||||
}
|
||||
if (lv_is_locked(origin_lv)) {
|
||||
@@ -7207,7 +7294,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
return_NULL;
|
||||
|
||||
/* The snapshot segment gets created later */
|
||||
if (!(create_segtype = get_segtype_from_string(cmd, "striped")))
|
||||
if (!(create_segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_NULL;
|
||||
|
||||
/* Must zero cow */
|
||||
@@ -7301,8 +7388,6 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
first_seg(lv)->chunk_size = lp->chunk_size;
|
||||
first_seg(lv)->zero_new_blocks = lp->zero ? 1 : 0;
|
||||
first_seg(lv)->discards = lp->discards;
|
||||
/* FIXME: use lowwatermark via lvm.conf global for all thinpools ? */
|
||||
first_seg(lv)->low_water_mark = 0;
|
||||
if (!recalculate_pool_chunk_size_with_dev_hints(lv, lp->passed_args,
|
||||
lp->thin_chunk_size_calc_policy)) {
|
||||
stack;
|
||||
@@ -7503,6 +7588,8 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
if (!cache_set_policy(first_seg(lv), lp->policy_name, lp->policy_settings))
|
||||
return_NULL; /* revert? */
|
||||
|
||||
cache_check_for_warns(first_seg(lv));
|
||||
|
||||
if (!lv_update_and_reload(lv)) {
|
||||
/* FIXME Do a better revert */
|
||||
log_error("Aborting. Manual intervention required.");
|
||||
@@ -7602,7 +7689,7 @@ struct logical_volume *lv_create_single(struct volume_group *vg,
|
||||
if (lp->create_pool && !seg_is_pool(lp)) {
|
||||
segtype = lp->segtype;
|
||||
if (seg_is_thin_volume(lp)) {
|
||||
if (!(lp->segtype = get_segtype_from_string(vg->cmd, "thin-pool")))
|
||||
if (!(lp->segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_THIN_POOL)))
|
||||
return_NULL;
|
||||
|
||||
if (!(lv = _lv_create_an_lv(vg, lp, lp->pool_name)))
|
||||
@@ -7614,7 +7701,7 @@ struct logical_volume *lv_create_single(struct volume_group *vg,
|
||||
return NULL;
|
||||
}
|
||||
/* origin_name is defined -> creates cache LV with new cache pool */
|
||||
if (!(lp->segtype = get_segtype_from_string(vg->cmd, "cache-pool")))
|
||||
if (!(lp->segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_CACHE_POOL)))
|
||||
return_NULL;
|
||||
|
||||
if (!(lv = _lv_create_an_lv(vg, lp, lp->pool_name)))
|
||||
|
||||
@@ -119,12 +119,24 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
|
||||
inc_error_count;
|
||||
}
|
||||
|
||||
if (lv_is_pool_metadata(lv) &&
|
||||
(!(seg2 = first_seg(lv)) || !(seg2 = find_pool_seg(seg2)) ||
|
||||
seg2->metadata_lv != lv)) {
|
||||
log_error("LV %s: segment 1 pool metadata LV does not point back to same LV",
|
||||
lv->name);
|
||||
inc_error_count;
|
||||
if (lv_is_pool_metadata(lv)) {
|
||||
if (!(seg2 = first_seg(lv)) || !(seg2 = find_pool_seg(seg2)) ||
|
||||
seg2->metadata_lv != lv) {
|
||||
log_error("LV %s: segment 1 pool metadata LV does not point back to same LV",
|
||||
lv->name);
|
||||
inc_error_count;
|
||||
}
|
||||
if (lv_is_thin_pool_metadata(lv) &&
|
||||
!strstr(lv->name, "_tmeta")) {
|
||||
log_error("LV %s: thin pool metadata LV does not use _tmeta",
|
||||
lv->name);
|
||||
inc_error_count;
|
||||
} else if (lv_is_cache_pool_metadata(lv) &&
|
||||
!strstr(lv->name, "_cmeta")) {
|
||||
log_error("LV %s: cache pool metadata LV does not use _cmeta",
|
||||
lv->name);
|
||||
inc_error_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -163,10 +163,9 @@
|
||||
/* vg_read and vg_read_for_update flags */
|
||||
#define READ_ALLOW_INCONSISTENT 0x00010000U
|
||||
#define READ_ALLOW_EXPORTED 0x00020000U
|
||||
#define READ_OK_NOTFOUND 0x00040000U
|
||||
#define READ_WARN_INCONSISTENT 0x00080000U
|
||||
|
||||
/* A meta-flag, useful with toollib for_each_* functions. */
|
||||
#define READ_FOR_UPDATE 0x00100000U
|
||||
#define READ_FOR_UPDATE 0x00100000U /* A meta-flag, useful with toollib for_each_* functions. */
|
||||
|
||||
/* vg's "read_status" field */
|
||||
#define FAILED_INCONSISTENT 0x00000001U
|
||||
@@ -455,7 +454,6 @@ struct lv_segment {
|
||||
struct lv_segment_area *meta_areas; /* For RAID */
|
||||
struct logical_volume *metadata_lv; /* For thin_pool */
|
||||
uint64_t transaction_id; /* For thin_pool, thin */
|
||||
uint64_t low_water_mark; /* For thin_pool */
|
||||
unsigned zero_new_blocks; /* For thin_pool */
|
||||
thin_discards_t discards; /* For thin_pool */
|
||||
struct dm_list thin_messages; /* For thin_pool */
|
||||
@@ -650,9 +648,9 @@ int lv_resize(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
* Return a handle to VG metadata.
|
||||
*/
|
||||
struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,
|
||||
const char *vgid, uint32_t flags, uint32_t lockd_state);
|
||||
const char *vgid, uint32_t read_flags, uint32_t lockd_state);
|
||||
struct volume_group *vg_read_for_update(struct cmd_context *cmd, const char *vg_name,
|
||||
const char *vgid, uint32_t flags, uint32_t lockd_state);
|
||||
const char *vgid, uint32_t read_flags, uint32_t lockd_state);
|
||||
|
||||
/*
|
||||
* Test validity of a VG handle.
|
||||
@@ -1158,6 +1156,7 @@ int cache_mode_is_set(const struct lv_segment *seg);
|
||||
int cache_set_mode(struct lv_segment *cache_seg, const char *str);
|
||||
int cache_set_policy(struct lv_segment *cache_seg, const char *name,
|
||||
const struct dm_config_tree *settings);
|
||||
void cache_check_for_warns(const struct lv_segment *seg);
|
||||
int update_cache_pool_params(const struct segment_type *segtype,
|
||||
struct volume_group *vg, unsigned attr,
|
||||
int passed_args, uint32_t pool_data_extents,
|
||||
|
||||
@@ -319,10 +319,11 @@ static struct pv_list *_copy_pvl(struct dm_pool *pvmem, struct pv_list *pvl_from
|
||||
if (!(pvl_to->pv = dm_pool_alloc(pvmem, sizeof(*pvl_to->pv))))
|
||||
goto_bad;
|
||||
|
||||
if(!_copy_pv(pvmem, pvl_to->pv, pvl_from->pv))
|
||||
if (!_copy_pv(pvmem, pvl_to->pv, pvl_from->pv))
|
||||
goto_bad;
|
||||
|
||||
return pvl_to;
|
||||
|
||||
bad:
|
||||
dm_pool_free(pvmem, pvl_to);
|
||||
return NULL;
|
||||
@@ -3010,7 +3011,7 @@ out:
|
||||
int vg_write(struct volume_group *vg)
|
||||
{
|
||||
struct dm_list *mdah;
|
||||
struct pv_to_create *pv_to_create;
|
||||
struct pv_to_create *pv_to_create, *pv_to_create_safe;
|
||||
struct metadata_area *mda;
|
||||
struct lv_list *lvl;
|
||||
int revert = 0, wrote = 0;
|
||||
@@ -3066,10 +3067,11 @@ int vg_write(struct volume_group *vg)
|
||||
memlock_unlock(vg->cmd);
|
||||
vg->seqno++;
|
||||
|
||||
dm_list_iterate_items(pv_to_create, &vg->pvs_to_create) {
|
||||
dm_list_iterate_items_safe(pv_to_create, pv_to_create_safe, &vg->pvs_to_create) {
|
||||
if (!_pvcreate_write(vg->cmd, pv_to_create))
|
||||
return 0;
|
||||
}
|
||||
dm_list_del(&pv_to_create->list);
|
||||
}
|
||||
|
||||
/* Write to each copy of the metadata area */
|
||||
dm_list_iterate_items(mda, &vg->fid->metadata_areas_in_use) {
|
||||
@@ -4923,7 +4925,7 @@ static int _vg_access_permitted(struct cmd_context *cmd, struct volume_group *vg
|
||||
* Consolidated locking, reading, and status flag checking.
|
||||
*
|
||||
* If the metadata is inconsistent, setting READ_ALLOW_INCONSISTENT in
|
||||
* misc_flags will return it with FAILED_INCONSISTENT set instead of
|
||||
* read_flags will return it with FAILED_INCONSISTENT set instead of
|
||||
* giving you nothing.
|
||||
*
|
||||
* Use vg_read_error(vg) to determine the result. Nonzero means there were
|
||||
@@ -4931,8 +4933,10 @@ static int _vg_access_permitted(struct cmd_context *cmd, struct volume_group *vg
|
||||
* Zero value means that the VG is open and appropriate locks are held.
|
||||
*/
|
||||
static struct volume_group *_vg_lock_and_read(struct cmd_context *cmd, const char *vg_name,
|
||||
const char *vgid, uint32_t lock_flags,
|
||||
uint64_t status_flags, uint32_t misc_flags,
|
||||
const char *vgid,
|
||||
uint32_t lock_flags,
|
||||
uint64_t status_flags,
|
||||
uint32_t read_flags,
|
||||
uint32_t lockd_state)
|
||||
{
|
||||
struct volume_group *vg = NULL;
|
||||
@@ -4942,7 +4946,7 @@ static struct volume_group *_vg_lock_and_read(struct cmd_context *cmd, const cha
|
||||
uint32_t warn_flags = 0;
|
||||
int already_locked;
|
||||
|
||||
if (misc_flags & READ_ALLOW_INCONSISTENT || lock_flags != LCK_VG_WRITE)
|
||||
if ((read_flags & READ_ALLOW_INCONSISTENT) || (lock_flags != LCK_VG_WRITE))
|
||||
consistent = 0;
|
||||
|
||||
if (!validate_name(vg_name) && !is_orphan_vg(vg_name)) {
|
||||
@@ -4965,7 +4969,7 @@ static struct volume_group *_vg_lock_and_read(struct cmd_context *cmd, const cha
|
||||
consistent_in = consistent;
|
||||
|
||||
warn_flags = WARN_PV_READ;
|
||||
if (consistent || (misc_flags & READ_WARN_INCONSISTENT))
|
||||
if (consistent || (read_flags & READ_WARN_INCONSISTENT))
|
||||
warn_flags |= WARN_INCONSISTENT;
|
||||
|
||||
/* If consistent == 1, we get NULL here if correction fails. */
|
||||
@@ -4974,7 +4978,8 @@ static struct volume_group *_vg_lock_and_read(struct cmd_context *cmd, const cha
|
||||
failure |= FAILED_INCONSISTENT;
|
||||
goto bad;
|
||||
}
|
||||
log_error("Volume group \"%s\" not found", vg_name);
|
||||
if (!(read_flags & READ_OK_NOTFOUND))
|
||||
log_error("Volume group \"%s\" not found", vg_name);
|
||||
failure |= FAILED_NOTFOUND;
|
||||
goto bad;
|
||||
}
|
||||
@@ -5055,20 +5060,20 @@ bad_no_unlock:
|
||||
* *consistent = 1.
|
||||
*/
|
||||
struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,
|
||||
const char *vgid, uint32_t flags, uint32_t lockd_state)
|
||||
const char *vgid, uint32_t read_flags, uint32_t lockd_state)
|
||||
{
|
||||
uint64_t status = UINT64_C(0);
|
||||
uint64_t status_flags = UINT64_C(0);
|
||||
uint32_t lock_flags = LCK_VG_READ;
|
||||
|
||||
if (flags & READ_FOR_UPDATE) {
|
||||
status |= EXPORTED_VG | LVM_WRITE;
|
||||
if (read_flags & READ_FOR_UPDATE) {
|
||||
status_flags |= EXPORTED_VG | LVM_WRITE;
|
||||
lock_flags = LCK_VG_WRITE;
|
||||
}
|
||||
|
||||
if (flags & READ_ALLOW_EXPORTED)
|
||||
status &= ~EXPORTED_VG;
|
||||
if (read_flags & READ_ALLOW_EXPORTED)
|
||||
status_flags &= ~EXPORTED_VG;
|
||||
|
||||
return _vg_lock_and_read(cmd, vg_name, vgid, lock_flags, status, flags, lockd_state);
|
||||
return _vg_lock_and_read(cmd, vg_name, vgid, lock_flags, status_flags, read_flags, lockd_state);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -5077,9 +5082,9 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,
|
||||
* request the new metadata to be written and committed).
|
||||
*/
|
||||
struct volume_group *vg_read_for_update(struct cmd_context *cmd, const char *vg_name,
|
||||
const char *vgid, uint32_t flags, uint32_t lockd_state)
|
||||
const char *vgid, uint32_t read_flags, uint32_t lockd_state)
|
||||
{
|
||||
return vg_read(cmd, vg_name, vgid, flags | READ_FOR_UPDATE, lockd_state);
|
||||
return vg_read(cmd, vg_name, vgid, read_flags | READ_FOR_UPDATE, lockd_state);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -83,7 +83,7 @@ int cluster_mirror_is_available(struct cmd_context *cmd)
|
||||
unsigned attr = 0;
|
||||
const struct segment_type *segtype;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "mirror")))
|
||||
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_MIRROR)))
|
||||
return_0;
|
||||
|
||||
if (!segtype->ops->target_present)
|
||||
@@ -112,7 +112,7 @@ uint32_t lv_mirror_count(const struct logical_volume *lv)
|
||||
seg = first_seg(lv);
|
||||
|
||||
/* FIXME: RAID10 only supports 2 copies right now */
|
||||
if (!strcmp(seg->segtype->name, "raid10"))
|
||||
if (seg_is_raid10(seg))
|
||||
return 2;
|
||||
|
||||
if (lv_is_pvmove(lv))
|
||||
@@ -1493,8 +1493,7 @@ static int _create_mimage_lvs(struct alloc_handle *ah,
|
||||
}
|
||||
} else {
|
||||
if (!lv_add_segment(ah, m * stripes, stripes, img_lvs[m],
|
||||
get_segtype_from_string(lv->vg->cmd,
|
||||
"striped"),
|
||||
get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_STRIPED),
|
||||
stripe_size, 0, 0)) {
|
||||
log_error("Aborting. Failed to add mirror image segment "
|
||||
"to %s. Remove new LV and retry.",
|
||||
@@ -1547,8 +1546,7 @@ int remove_mirrors_from_segments(struct logical_volume *lv,
|
||||
seg->area_count = new_mirrors + 1;
|
||||
|
||||
if (!new_mirrors)
|
||||
seg->segtype = get_segtype_from_string(lv->vg->cmd,
|
||||
"striped");
|
||||
seg->segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_STRIPED);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -1720,7 +1718,7 @@ int fixup_imported_mirrors(struct volume_group *vg)
|
||||
dm_list_iterate_items(lvl, &vg->lvs) {
|
||||
dm_list_iterate_items(seg, &lvl->lv->segments) {
|
||||
if (seg->segtype !=
|
||||
get_segtype_from_string(vg->cmd, "mirror"))
|
||||
get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_MIRROR))
|
||||
continue;
|
||||
|
||||
if (seg->log_lv && !add_seg_to_segs_using_this_lv(seg->log_lv, seg))
|
||||
@@ -1748,7 +1746,7 @@ static int _add_mirrors_that_preserve_segments(struct logical_volume *lv,
|
||||
if (!(parallel_areas = build_parallel_areas_from_lv(lv, 1, 0)))
|
||||
return_0;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "mirror")))
|
||||
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_MIRROR)))
|
||||
return_0;
|
||||
|
||||
adjusted_region_size = adjusted_mirror_region_size(lv->vg->extent_size,
|
||||
@@ -2033,7 +2031,7 @@ int add_mirror_log(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
if (!(parallel_areas = build_parallel_areas_from_lv(lv, 0, 0)))
|
||||
return_0;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "mirror")))
|
||||
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_MIRROR)))
|
||||
return_0;
|
||||
|
||||
if (activation() && segtype->ops->target_present &&
|
||||
@@ -2106,7 +2104,7 @@ int add_mirror_images(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
if (!(parallel_areas = build_parallel_areas_from_lv(lv, 0, 0)))
|
||||
return_0;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "mirror")))
|
||||
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_MIRROR)))
|
||||
return_0;
|
||||
|
||||
ah = allocate_extents(lv->vg, NULL, segtype,
|
||||
|
||||
@@ -438,7 +438,7 @@ int create_pool(struct logical_volume *pool_lv,
|
||||
}
|
||||
|
||||
/* LV is not yet a pool, so it's extension from lvcreate */
|
||||
if (!(striped = get_segtype_from_string(pool_lv->vg->cmd, "striped")))
|
||||
if (!(striped = get_segtype_from_string(pool_lv->vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
if (activation() && striped->ops->target_present &&
|
||||
@@ -561,7 +561,7 @@ struct logical_volume *alloc_pool_metadata(struct logical_volume *pool_lv,
|
||||
.zero = 1,
|
||||
};
|
||||
|
||||
if (!(lvc.segtype = get_segtype_from_string(pool_lv->vg->cmd, "striped")))
|
||||
if (!(lvc.segtype = get_segtype_from_string(pool_lv->vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
/* FIXME: allocate properly space for metadata_lv */
|
||||
@@ -597,7 +597,7 @@ static struct logical_volume *_alloc_pool_metadata_spare(struct volume_group *vg
|
||||
.zero = 1,
|
||||
};
|
||||
|
||||
if (!(lp.segtype = get_segtype_from_string(vg->cmd, "striped")))
|
||||
if (!(lp.segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
/* FIXME: Maybe using silent mode ? */
|
||||
|
||||
@@ -29,9 +29,9 @@ char *pv_fmt_dup(const struct physical_volume *pv)
|
||||
return dm_pool_strdup(pv->vg->vgmem, pv->fmt->name);
|
||||
}
|
||||
|
||||
char *pv_name_dup(const struct physical_volume *pv)
|
||||
char *pv_name_dup(struct dm_pool *mem, const struct physical_volume *pv)
|
||||
{
|
||||
return dm_pool_strdup(pv->vg->vgmem, dev_name(pv->dev));
|
||||
return dm_pool_strdup(mem ? mem : pv->vg->vgmem, dev_name(pv->dev));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -42,9 +42,9 @@ struct id pv_id(const struct physical_volume *pv)
|
||||
return pv_field(pv, id);
|
||||
}
|
||||
|
||||
char *pv_uuid_dup(const struct physical_volume *pv)
|
||||
char *pv_uuid_dup(struct dm_pool *mem, const struct physical_volume *pv)
|
||||
{
|
||||
return id_format_and_copy(pv->vg->vgmem, &pv->id);
|
||||
return id_format_and_copy(mem ? mem : pv->vg->vgmem, &pv->id);
|
||||
}
|
||||
|
||||
char *pv_tags_dup(const struct physical_volume *pv)
|
||||
|
||||
@@ -68,12 +68,12 @@ struct physical_volume {
|
||||
};
|
||||
|
||||
char *pv_fmt_dup(const struct physical_volume *pv);
|
||||
char *pv_name_dup(const struct physical_volume *pv);
|
||||
char *pv_name_dup(struct dm_pool *mem, const struct physical_volume *pv);
|
||||
struct device *pv_dev(const struct physical_volume *pv);
|
||||
const char *pv_vg_name(const struct physical_volume *pv);
|
||||
char *pv_attr_dup(struct dm_pool *mem, const struct physical_volume *pv);
|
||||
const char *pv_dev_name(const struct physical_volume *pv);
|
||||
char *pv_uuid_dup(const struct physical_volume *pv);
|
||||
char *pv_uuid_dup(struct dm_pool *mem, const struct physical_volume *pv);
|
||||
char *pv_tags_dup(const struct physical_volume *pv);
|
||||
uint64_t pv_size(const struct physical_volume *pv);
|
||||
uint64_t pv_size_field(const struct physical_volume *pv);
|
||||
|
||||
@@ -781,7 +781,7 @@ int pvremove_single(struct cmd_context *cmd, const char *pv_name,
|
||||
goto out;
|
||||
}
|
||||
|
||||
info = lvmcache_info_from_pvid(dev->pvid, 1);
|
||||
info = lvmcache_info_from_pvid(dev->pvid, 0);
|
||||
|
||||
if (!dev_test_excl(dev)) {
|
||||
/* FIXME Detect whether device-mapper is still using the device */
|
||||
|
||||
@@ -408,7 +408,7 @@ static struct logical_volume *_alloc_image_component(struct logical_volume *lv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, "striped")))
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
if (!lv_add_segment(ah, first_area, 1, tmp_lv, segtype, 0, status, 0)) {
|
||||
@@ -460,9 +460,12 @@ static int _alloc_image_components(struct logical_volume *lv,
|
||||
* individual devies, we must specify how large the individual device
|
||||
* is along with the number we want ('count').
|
||||
*/
|
||||
extents = (segtype->parity_devs) ?
|
||||
(lv->le_count / (seg->area_count - segtype->parity_devs)) :
|
||||
lv->le_count;
|
||||
if (segtype_is_raid10(segtype))
|
||||
extents = lv->le_count / (seg->area_count / 2); /* we enforce 2 mirrors right now */
|
||||
else
|
||||
extents = (segtype->parity_devs) ?
|
||||
(lv->le_count / (seg->area_count - segtype->parity_devs)) :
|
||||
lv->le_count;
|
||||
|
||||
if (!(ah = allocate_extents(lv->vg, NULL, segtype, 0, count, count,
|
||||
region_size, extents, pvs,
|
||||
@@ -867,7 +870,7 @@ static int _raid_extract_images(struct logical_volume *lv, uint32_t new_count,
|
||||
sizeof(*lvl_array) * extract * 2)))
|
||||
return_0;
|
||||
|
||||
if (!(error_segtype = get_segtype_from_string(lv->vg->cmd, "error")))
|
||||
if (!(error_segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_ERROR)))
|
||||
return_0;
|
||||
|
||||
/*
|
||||
@@ -1102,7 +1105,7 @@ int lv_raid_split(struct logical_volume *lv, const char *split_name,
|
||||
}
|
||||
|
||||
if (!seg_is_mirrored(first_seg(lv)) ||
|
||||
!strcmp(first_seg(lv)->segtype->name, SEG_TYPE_NAME_RAID10)) {
|
||||
seg_is_raid10(first_seg(lv))) {
|
||||
log_error("Unable to split logical volume of segment type, %s",
|
||||
lvseg_name(first_seg(lv)));
|
||||
return 0;
|
||||
@@ -1475,13 +1478,11 @@ int lv_raid_reshape(struct logical_volume *lv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(seg->segtype->name, "mirror") &&
|
||||
(!strcmp(new_segtype->name, SEG_TYPE_NAME_RAID1)))
|
||||
return _convert_mirror_to_raid1(lv, new_segtype);
|
||||
if (seg_is_mirror(seg) && segtype_is_raid1(new_segtype))
|
||||
return _convert_mirror_to_raid1(lv, new_segtype);
|
||||
|
||||
log_error("Converting the segment type for %s/%s from %s to %s"
|
||||
" is not yet supported.", lv->vg->name, lv->name,
|
||||
lvseg_name(seg), new_segtype->name);
|
||||
log_error("Converting the segment type for %s/%s from %s to %s is not yet supported.",
|
||||
lv->vg->name, lv->name, lvseg_name(seg), new_segtype->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1663,7 +1664,7 @@ int lv_raid_replace(struct logical_volume *lv,
|
||||
lvseg_name(raid_seg),
|
||||
lv->vg->name, lv->name);
|
||||
return 0;
|
||||
} else if (!strcmp(raid_seg->segtype->name, SEG_TYPE_NAME_RAID10)) {
|
||||
} else if (seg_is_raid10(raid_seg)) {
|
||||
uint32_t i, rebuilds_per_group = 0;
|
||||
/* FIXME: We only support 2-way mirrors in RAID10 currently */
|
||||
uint32_t copies = 2;
|
||||
@@ -1895,7 +1896,7 @@ static int _partial_raid_lv_is_redundant(const struct logical_volume *lv)
|
||||
uint32_t i, s, rebuilds_per_group = 0;
|
||||
uint32_t failed_components = 0;
|
||||
|
||||
if (!strcmp(raid_seg->segtype->name, SEG_TYPE_NAME_RAID10)) {
|
||||
if (seg_is_raid10(raid_seg)) {
|
||||
/* FIXME: We only support 2-way mirrors in RAID10 currently */
|
||||
copies = 2;
|
||||
for (i = 0; i < raid_seg->area_count * copies; i++) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -28,32 +28,95 @@ struct dm_config_node;
|
||||
struct dev_manager;
|
||||
|
||||
/* Feature flags */
|
||||
#define SEG_CAN_SPLIT 0x00000001U
|
||||
#define SEG_AREAS_STRIPED 0x00000002U
|
||||
#define SEG_AREAS_MIRRORED 0x00000004U
|
||||
#define SEG_SNAPSHOT 0x00000008U
|
||||
#define SEG_FORMAT1_SUPPORT 0x00000010U
|
||||
#define SEG_VIRTUAL 0x00000020U
|
||||
#define SEG_CANNOT_BE_ZEROED 0x00000040U
|
||||
#define SEG_MONITORED 0x00000080U
|
||||
#define SEG_REPLICATOR 0x00000100U
|
||||
#define SEG_REPLICATOR_DEV 0x00000200U
|
||||
#define SEG_RAID 0x00000400U
|
||||
#define SEG_THIN_POOL 0x00000800U
|
||||
#define SEG_THIN_VOLUME 0x00001000U
|
||||
#define SEG_CACHE 0x00002000U
|
||||
#define SEG_CACHE_POOL 0x00004000U
|
||||
#define SEG_MIRROR 0x00008000U
|
||||
#define SEG_ONLY_EXCLUSIVE 0x00010000U /* In cluster only exlusive activation */
|
||||
#define SEG_CAN_ERROR_WHEN_FULL 0x00020000U
|
||||
#define SEG_UNKNOWN 0x80000000U
|
||||
#define SEG_CAN_SPLIT 0x0000000000000001ULL
|
||||
#define SEG_AREAS_STRIPED 0x0000000000000002ULL
|
||||
#define SEG_AREAS_MIRRORED 0x0000000000000004ULL
|
||||
#define SEG_SNAPSHOT 0x0000000000000008ULL
|
||||
#define SEG_FORMAT1_SUPPORT 0x0000000000000010ULL
|
||||
#define SEG_VIRTUAL 0x0000000000000020ULL
|
||||
#define SEG_CANNOT_BE_ZEROED 0x0000000000000040ULL
|
||||
#define SEG_MONITORED 0x0000000000000080ULL
|
||||
#define SEG_REPLICATOR 0x0000000000000100ULL
|
||||
#define SEG_REPLICATOR_DEV 0x0000000000000200ULL
|
||||
#define SEG_RAID 0x0000000000000400ULL
|
||||
#define SEG_THIN_POOL 0x0000000000000800ULL
|
||||
#define SEG_THIN_VOLUME 0x0000000000001000ULL
|
||||
#define SEG_CACHE 0x0000000000002000ULL
|
||||
#define SEG_CACHE_POOL 0x0000000000004000ULL
|
||||
#define SEG_MIRROR 0x0000000000008000ULL
|
||||
#define SEG_ONLY_EXCLUSIVE 0x0000000000010000ULL /* In cluster only exlusive activation */
|
||||
#define SEG_CAN_ERROR_WHEN_FULL 0x0000000000020000ULL
|
||||
|
||||
#define SEG_RAID1 0x0000000000100000ULL
|
||||
#define SEG_RAID10 0x0000000000200000ULL
|
||||
#define SEG_RAID4 0x0000000000400000ULL
|
||||
#define SEG_RAID5_N 0x0000000000800000ULL
|
||||
#define SEG_RAID5_LA 0x0000000001000000ULL
|
||||
#define SEG_RAID5_LS 0x0000000002000000ULL
|
||||
#define SEG_RAID5_RA 0x0000000004000000ULL
|
||||
#define SEG_RAID5_RS 0x0000000008000000ULL
|
||||
#define SEG_RAID5 SEG_RAID5_LS
|
||||
#define SEG_RAID6_NC 0x0000000010000000ULL
|
||||
#define SEG_RAID6_NR 0x0000000020000000ULL
|
||||
#define SEG_RAID6_ZR 0x0000000040000000ULL
|
||||
#define SEG_RAID6_LA_6 0x0000000080000000ULL
|
||||
#define SEG_RAID6_LS_6 0x0000000100000000ULL
|
||||
#define SEG_RAID6_RA_6 0x0000000200000000ULL
|
||||
#define SEG_RAID6_RS_6 0x0000000400000000ULL
|
||||
#define SEG_RAID6_N_6 0x0000000800000000ULL
|
||||
#define SEG_RAID6 SEG_RAID6_ZR
|
||||
|
||||
#define SEG_UNKNOWN 0x8000000000000000ULL
|
||||
|
||||
#define SEG_TYPE_NAME_LINEAR "linear"
|
||||
#define SEG_TYPE_NAME_STRIPED "striped"
|
||||
#define SEG_TYPE_NAME_MIRROR "mirror"
|
||||
#define SEG_TYPE_NAME_SNAPSHOT "snapshot"
|
||||
#define SEG_TYPE_NAME_THIN "thin"
|
||||
#define SEG_TYPE_NAME_THIN_POOL "thin-pool"
|
||||
#define SEG_TYPE_NAME_CACHE "cache"
|
||||
#define SEG_TYPE_NAME_CACHE_POOL "cache-pool"
|
||||
#define SEG_TYPE_NAME_ERROR "error"
|
||||
#define SEG_TYPE_NAME_FREE "free"
|
||||
#define SEG_TYPE_NAME_ZERO "zero"
|
||||
#define SEG_TYPE_NAME_RAID "raid"
|
||||
#define SEG_TYPE_NAME_RAID0 "raid0"
|
||||
#define SEG_TYPE_NAME_RAID1 "raid1"
|
||||
#define SEG_TYPE_NAME_RAID10 "raid10"
|
||||
#define SEG_TYPE_NAME_RAID4 "raid4"
|
||||
#define SEG_TYPE_NAME_RAID5 "raid5"
|
||||
#define SEG_TYPE_NAME_RAID5_LA "raid5_la"
|
||||
#define SEG_TYPE_NAME_RAID5_LS "raid5_ls"
|
||||
#define SEG_TYPE_NAME_RAID5_RA "raid5_ra"
|
||||
#define SEG_TYPE_NAME_RAID5_RS "raid5_rs"
|
||||
#define SEG_TYPE_NAME_RAID6 "raid6"
|
||||
#define SEG_TYPE_NAME_RAID6_NC "raid6_nc"
|
||||
#define SEG_TYPE_NAME_RAID6_NR "raid6_nr"
|
||||
#define SEG_TYPE_NAME_RAID6_ZR "raid6_zr"
|
||||
|
||||
#define segtype_is_linear(segtype) (!strcmp(segtype->name, SEG_TYPE_NAME_LINEAR))
|
||||
#define segtype_is_cache(segtype) ((segtype)->flags & SEG_CACHE ? 1 : 0)
|
||||
#define segtype_is_cache_pool(segtype) ((segtype)->flags & SEG_CACHE_POOL ? 1 : 0)
|
||||
#define segtype_is_mirrored(segtype) ((segtype)->flags & SEG_AREAS_MIRRORED ? 1 : 0)
|
||||
#define segtype_is_mirror(segtype) ((segtype)->flags & SEG_MIRROR ? 1 : 0)
|
||||
#define segtype_is_pool(segtype) ((segtype)->flags & (SEG_CACHE_POOL | SEG_THIN_POOL) ? 1 : 0)
|
||||
#define segtype_is_raid(segtype) ((segtype)->flags & SEG_RAID ? 1 : 0)
|
||||
#define segtype_is_raid1(segtype) ((segtype)->flags & SEG_RAID1 ? 1 : 0)
|
||||
#define segtype_is_raid4(segtype) ((segtype)->flags & SEG_RAID4 ? 1 : 0)
|
||||
#define segtype_is_any_raid5(segtype) ((segtype)->flags & \
|
||||
(SEG_RAID5_LS|SEG_RAID5_LA|SEG_RAID5_RS|SEG_RAID5_RA|SEG_RAID5_N) ? 1 : 0)
|
||||
#define segtype_is_raid5_la(segtype) ((segtype)->flags & SEG_RAID5_LA ? 1 : 0)
|
||||
#define segtype_is_raid5_ra(segtype) ((segtype)->flags & SEG_RAID5_RA ? 1 : 0)
|
||||
#define segtype_is_raid5_ls(segtype) ((segtype)->flags & SEG_RAID5_LS ? 1 : 0)
|
||||
#define segtype_is_raid5_rs(segtype) ((segtype)->flags & SEG_RAID5_RS ? 1 : 0)
|
||||
#define segtype_is_any_raid6(segtype) ((segtype)->flags & \
|
||||
(SEG_RAID6_ZR|SEG_RAID6_NC|SEG_RAID6_NR| \
|
||||
SEG_RAID6_LA_6|SEG_RAID6_LS_6|SEG_RAID6_RA_6|SEG_RAID6_RS_6|SEG_RAID6_N_6) ? 1 : 0)
|
||||
#define segtype_is_raid6_nc(segtype) ((segtype)->flags & SEG_RAID6_NC ? 1 : 0)
|
||||
#define segtype_is_raid6_nr(segtype) ((segtype)->flags & SEG_RAID6_NR ? 1 : 0)
|
||||
#define segtype_is_raid6_zr(segtype) ((segtype)->flags & SEG_RAID6_ZR ? 1 : 0)
|
||||
#define segtype_is_raid10(segtype) ((segtype)->flags & SEG_RAID10 ? 1 : 0)
|
||||
#define segtype_is_snapshot(segtype) ((segtype)->flags & SEG_SNAPSHOT ? 1 : 0)
|
||||
#define segtype_is_striped(segtype) ((segtype)->flags & SEG_AREAS_STRIPED ? 1 : 0)
|
||||
#define segtype_is_thin(segtype) ((segtype)->flags & (SEG_THIN_POOL|SEG_THIN_VOLUME) ? 1 : 0)
|
||||
#define segtype_is_thin_pool(segtype) ((segtype)->flags & SEG_THIN_POOL ? 1 : 0)
|
||||
@@ -68,9 +131,21 @@ struct dev_manager;
|
||||
#define seg_is_mirrored(seg) segtype_is_mirrored((seg)->segtype)
|
||||
#define seg_is_pool(seg) segtype_is_pool((seg)->segtype)
|
||||
#define seg_is_raid(seg) segtype_is_raid((seg)->segtype)
|
||||
#define seg_is_raid1(seg) segtype_is_raid1((seg)->segtype)
|
||||
#define seg_is_raid4(seg) segtype_is_raid4((seg)->segtype)
|
||||
#define seg_is_any_raid5(seg) segtype_is_any_raid5((seg)->segtype)
|
||||
#define seg_is_raid5_la(seg) segtype_is_raid5_la((seg)->segtype)
|
||||
#define seg_is_raid5_ra(seg) segtype_is_raid5_ra((seg)->segtype)
|
||||
#define seg_is_raid5_ls(seg) segtype_is_raid5_ls((seg)->segtype)
|
||||
#define seg_is_raid5_rs(seg) segtype_is_raid5_rs((seg)->segtype)
|
||||
#define seg_is_any_raid6(seg) segtype_is_any_raid6((seg)->segtype)
|
||||
#define seg_is_raid6_zr(seg) segtype_is_raid6_zr((seg)->segtype)
|
||||
#define seg_is_raid6_nr(seg) segtype_is_raid6_nr((seg)->segtype)
|
||||
#define seg_is_raid6_nc(seg) segtype_is_raid6_nc((seg)->segtype)
|
||||
#define seg_is_raid10(seg) segtype_is_raid10((seg)->segtype)
|
||||
#define seg_is_replicator(seg) ((seg)->segtype->flags & SEG_REPLICATOR ? 1 : 0)
|
||||
#define seg_is_replicator_dev(seg) ((seg)->segtype->flags & SEG_REPLICATOR_DEV ? 1 : 0)
|
||||
#define seg_is_snapshot(seg) ((seg)->segtype->flags & SEG_SNAPSHOT ? 1 : 0)
|
||||
#define seg_is_snapshot(seg) segtype_is_snapshot((seg)->segtype)
|
||||
#define seg_is_striped(seg) segtype_is_striped((seg)->segtype)
|
||||
#define seg_is_thin(seg) segtype_is_thin((seg)->segtype)
|
||||
#define seg_is_thin_pool(seg) segtype_is_thin_pool((seg)->segtype)
|
||||
@@ -86,8 +161,8 @@ struct dev_manager;
|
||||
struct segment_type {
|
||||
struct dm_list list; /* Internal */
|
||||
|
||||
uint32_t flags;
|
||||
uint32_t parity_devs; /* Parity drives required by segtype */
|
||||
uint64_t flags;
|
||||
uint32_t parity_devs; /* Parity drives required by segtype */
|
||||
|
||||
struct segtype_handler *ops;
|
||||
const char *name;
|
||||
@@ -152,24 +227,13 @@ struct segment_type *init_unknown_segtype(struct cmd_context *cmd,
|
||||
const char *name);
|
||||
|
||||
#define RAID_FEATURE_RAID10 (1U << 0) /* version 1.3 */
|
||||
#define RAID_FEATURE_RAID0 (1U << 1) /* version 1.7 */
|
||||
#define RAID_FEATURE_RESHAPING (1U << 2) /* version 1.8 */
|
||||
|
||||
#ifdef RAID_INTERNAL
|
||||
int init_raid_segtypes(struct cmd_context *cmd, struct segtype_library *seglib);
|
||||
#endif
|
||||
|
||||
#define SEG_TYPE_NAME_RAID1 "raid1"
|
||||
#define SEG_TYPE_NAME_RAID10 "raid10"
|
||||
#define SEG_TYPE_NAME_RAID4 "raid4"
|
||||
#define SEG_TYPE_NAME_RAID5 "raid5"
|
||||
#define SEG_TYPE_NAME_RAID5_LA "raid5_la"
|
||||
#define SEG_TYPE_NAME_RAID5_LS "raid5_ls"
|
||||
#define SEG_TYPE_NAME_RAID5_RA "raid5_ra"
|
||||
#define SEG_TYPE_NAME_RAID5_RS "raid5_rs"
|
||||
#define SEG_TYPE_NAME_RAID6 "raid6"
|
||||
#define SEG_TYPE_NAME_RAID6_NC "raid6_nc"
|
||||
#define SEG_TYPE_NAME_RAID6_NR "raid6_nr"
|
||||
#define SEG_TYPE_NAME_RAID6_ZR "raid6_zr"
|
||||
|
||||
#ifdef REPLICATOR_INTERNAL
|
||||
int init_replicator_segtype(struct cmd_context *cmd, struct segtype_library *seglib);
|
||||
#endif
|
||||
|
||||
@@ -44,7 +44,7 @@ static uint64_t _cow_extra_chunks(struct cmd_context *cmd, uint64_t n_chunks)
|
||||
unsigned attrs = 0;
|
||||
|
||||
if (activation() &&
|
||||
(segtype = get_segtype_from_string(cmd, "snapshot")) &&
|
||||
(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_SNAPSHOT)) &&
|
||||
segtype->ops->target_present &&
|
||||
segtype->ops->target_present(cmd, NULL, &attrs) &&
|
||||
(attrs & SNAPSHOT_FEATURE_FIXED_LEAK))
|
||||
|
||||
@@ -216,7 +216,7 @@ int thin_pool_feature_supported(const struct logical_volume *lv, int feature)
|
||||
int pool_below_threshold(const struct lv_segment *pool_seg)
|
||||
{
|
||||
dm_percent_t percent;
|
||||
int threshold = DM_PERCENT_1 *
|
||||
dm_percent_t threshold = DM_PERCENT_1 *
|
||||
find_config_tree_int(pool_seg->lv->vg->cmd, activation_thin_pool_autoextend_threshold_CFG,
|
||||
lv_config_profile(pool_seg->lv));
|
||||
|
||||
@@ -224,15 +224,27 @@ int pool_below_threshold(const struct lv_segment *pool_seg)
|
||||
if (!lv_thin_pool_percent(pool_seg->lv, 0, &percent))
|
||||
return_0;
|
||||
|
||||
if (percent >= threshold)
|
||||
if (percent > threshold) {
|
||||
log_debug("Threshold configured for free data space in "
|
||||
"thin pool %s has been reached (%.2f%% >= %.2f%%).",
|
||||
display_lvname(pool_seg->lv),
|
||||
dm_percent_to_float(percent),
|
||||
dm_percent_to_float(threshold));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Metadata */
|
||||
if (!lv_thin_pool_percent(pool_seg->lv, 1, &percent))
|
||||
return_0;
|
||||
|
||||
if (percent >= threshold)
|
||||
if (percent > threshold) {
|
||||
log_debug("Threshold configured for free metadata space in "
|
||||
"thin pool %s has been reached (%.2f%% > %.2f%%).",
|
||||
display_lvname(pool_seg->lv),
|
||||
dm_percent_to_float(percent),
|
||||
dm_percent_to_float(threshold));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -620,7 +620,7 @@ struct segment_type *init_segtype(struct cmd_context *cmd)
|
||||
return_NULL;
|
||||
|
||||
segtype->ops = &_mirrored_ops;
|
||||
segtype->name = "mirror";
|
||||
segtype->name = SEG_TYPE_NAME_MIRROR;
|
||||
segtype->flags = SEG_MIRROR | SEG_AREAS_MIRRORED;
|
||||
|
||||
#ifdef DEVMAPPER_SUPPORT
|
||||
|
||||
2
lib/misc/.gitignore
vendored
2
lib/misc/.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
configure.h
|
||||
lvm-version.h
|
||||
@@ -40,6 +40,8 @@ static int _security_level = SECURITY_LEVEL;
|
||||
static char _cmd_name[30] = "";
|
||||
static int _mirror_in_sync = 0;
|
||||
static int _dmeventd_monitor = DEFAULT_DMEVENTD_MONITOR;
|
||||
/* When set, disables update of _dmeventd_monitor & _ignore_suspended_devices */
|
||||
static int _disable_dmeventd_monitoring = 0;
|
||||
static int _background_polling = DEFAULT_BACKGROUND_POLLING;
|
||||
static int _ignore_suspended_devices = 0;
|
||||
static int _ignore_lvm_mirrors = DEFAULT_IGNORE_LVM_MIRRORS;
|
||||
@@ -123,7 +125,13 @@ void init_mirror_in_sync(int in_sync)
|
||||
|
||||
void init_dmeventd_monitor(int reg)
|
||||
{
|
||||
_dmeventd_monitor = reg;
|
||||
if (!_disable_dmeventd_monitoring)
|
||||
_dmeventd_monitor = reg;
|
||||
}
|
||||
|
||||
void init_disable_dmeventd_monitoring(int reg)
|
||||
{
|
||||
_disable_dmeventd_monitoring = reg;
|
||||
}
|
||||
|
||||
void init_background_polling(int polling)
|
||||
@@ -133,7 +141,8 @@ void init_background_polling(int polling)
|
||||
|
||||
void init_ignore_suspended_devices(int ignore)
|
||||
{
|
||||
_ignore_suspended_devices = ignore;
|
||||
if (!_disable_dmeventd_monitoring)
|
||||
_ignore_suspended_devices = ignore;
|
||||
}
|
||||
|
||||
void init_ignore_lvm_mirrors(int scan)
|
||||
|
||||
@@ -38,6 +38,7 @@ void init_lockingfailed(int level);
|
||||
void init_security_level(int level);
|
||||
void init_mirror_in_sync(int in_sync);
|
||||
void init_dmeventd_monitor(int reg);
|
||||
void init_disable_dmeventd_monitoring(int disable);
|
||||
void init_background_polling(int polling);
|
||||
void init_ignore_suspended_devices(int ignore);
|
||||
void init_ignore_lvm_mirrors(int scan);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "lib.h"
|
||||
#include "lvm-signal.h"
|
||||
#include "memlock.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
@@ -60,6 +61,8 @@ void sigint_allow(void)
|
||||
struct sigaction handler;
|
||||
sigset_t sigs;
|
||||
|
||||
if (memlock_count_daemon())
|
||||
return;
|
||||
/*
|
||||
* Do not overwrite the backed-up handler data -
|
||||
* just increase nesting count.
|
||||
@@ -91,6 +94,9 @@ void sigint_allow(void)
|
||||
|
||||
void sigint_restore(void)
|
||||
{
|
||||
if (memlock_count_daemon())
|
||||
return;
|
||||
|
||||
if (!_handler_installed ||
|
||||
--_handler_installed >= MAX_SIGINTS)
|
||||
return;
|
||||
@@ -112,6 +118,9 @@ void block_signals(uint32_t flags __attribute__((unused)))
|
||||
{
|
||||
sigset_t set;
|
||||
|
||||
if (memlock_count_daemon())
|
||||
return;
|
||||
|
||||
if (_signals_blocked)
|
||||
return;
|
||||
|
||||
@@ -130,6 +139,9 @@ void block_signals(uint32_t flags __attribute__((unused)))
|
||||
|
||||
void unblock_signals(void)
|
||||
{
|
||||
if (memlock_count_daemon())
|
||||
return;
|
||||
|
||||
/* Don't unblock signals while any locks are held */
|
||||
if (!_signals_blocked)
|
||||
return;
|
||||
|
||||
@@ -638,3 +638,8 @@ void memlock_unlock(struct cmd_context *cmd)
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int memlock_count_daemon(void)
|
||||
{
|
||||
return _memlock_count_daemon;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ void critical_section_dec(struct cmd_context *cmd, const char *reason);
|
||||
int critical_section(void);
|
||||
void memlock_inc_daemon(struct cmd_context *cmd);
|
||||
void memlock_dec_daemon(struct cmd_context *cmd);
|
||||
int memlock_count_daemon(void);
|
||||
void memlock_init(struct cmd_context *cmd);
|
||||
void memlock_reset(void);
|
||||
void memlock_unlock(struct cmd_context *cmd);
|
||||
|
||||
112
lib/raid/raid.c
112
lib/raid/raid.c
@@ -55,7 +55,7 @@ static int _raid_text_import_areas(struct lv_segment *seg,
|
||||
const struct dm_config_value *cv)
|
||||
{
|
||||
unsigned int s;
|
||||
struct logical_volume *lv1;
|
||||
struct logical_volume *lv;
|
||||
const char *seg_name = dm_config_parent_name(sn);
|
||||
|
||||
if (!seg->area_count) {
|
||||
@@ -75,23 +75,23 @@ static int _raid_text_import_areas(struct lv_segment *seg,
|
||||
}
|
||||
|
||||
/* Metadata device comes first */
|
||||
if (!(lv1 = find_lv(seg->lv->vg, cv->v.str))) {
|
||||
if (!(lv = find_lv(seg->lv->vg, cv->v.str))) {
|
||||
log_error("Couldn't find volume '%s' for segment '%s'.",
|
||||
cv->v.str ? : "NULL", seg_name);
|
||||
return 0;
|
||||
}
|
||||
if (!set_lv_segment_area_lv(seg, s, lv1, 0, RAID_META))
|
||||
return_0;
|
||||
if (!set_lv_segment_area_lv(seg, s, lv, 0, RAID_META))
|
||||
return_0;
|
||||
|
||||
/* Data device comes second */
|
||||
cv = cv->next;
|
||||
if (!(lv1 = find_lv(seg->lv->vg, cv->v.str))) {
|
||||
if (!(lv = find_lv(seg->lv->vg, cv->v.str))) {
|
||||
log_error("Couldn't find volume '%s' for segment '%s'.",
|
||||
cv->v.str ? : "NULL", seg_name);
|
||||
return 0;
|
||||
}
|
||||
if (!set_lv_segment_area_lv(seg, s, lv1, 0, RAID_IMAGE))
|
||||
return_0;
|
||||
if (!set_lv_segment_area_lv(seg, s, lv, 0, RAID_IMAGE))
|
||||
return_0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -111,49 +111,28 @@ static int _raid_text_import(struct lv_segment *seg,
|
||||
struct dm_hash_table *pv_hash)
|
||||
{
|
||||
const struct dm_config_value *cv;
|
||||
const struct {
|
||||
const char *name;
|
||||
uint32_t *var;
|
||||
} raid_attr_import[] = {
|
||||
{ "region_size", &seg->region_size },
|
||||
{ "stripe_size", &seg->stripe_size },
|
||||
{ "writebehind", &seg->writebehind },
|
||||
{ "min_recovery_rate", &seg->min_recovery_rate },
|
||||
{ "max_recovery_rate", &seg->max_recovery_rate },
|
||||
}, *aip = raid_attr_import;
|
||||
int i;
|
||||
|
||||
if (dm_config_has_node(sn, "region_size")) {
|
||||
if (!dm_config_get_uint32(sn, "region_size", &seg->region_size)) {
|
||||
log_error("Couldn't read 'region_size' for "
|
||||
"segment %s of logical volume %s.",
|
||||
dm_config_parent_name(sn), seg->lv->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (dm_config_has_node(sn, "stripe_size")) {
|
||||
if (!dm_config_get_uint32(sn, "stripe_size", &seg->stripe_size)) {
|
||||
log_error("Couldn't read 'stripe_size' for "
|
||||
"segment %s of logical volume %s.",
|
||||
dm_config_parent_name(sn), seg->lv->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (dm_config_has_node(sn, "writebehind")) {
|
||||
if (!dm_config_get_uint32(sn, "writebehind", &seg->writebehind)) {
|
||||
log_error("Couldn't read 'writebehind' for "
|
||||
"segment %s of logical volume %s.",
|
||||
dm_config_parent_name(sn), seg->lv->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (dm_config_has_node(sn, "min_recovery_rate")) {
|
||||
if (!dm_config_get_uint32(sn, "min_recovery_rate",
|
||||
&seg->min_recovery_rate)) {
|
||||
log_error("Couldn't read 'min_recovery_rate' for "
|
||||
"segment %s of logical volume %s.",
|
||||
dm_config_parent_name(sn), seg->lv->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (dm_config_has_node(sn, "max_recovery_rate")) {
|
||||
if (!dm_config_get_uint32(sn, "max_recovery_rate",
|
||||
&seg->max_recovery_rate)) {
|
||||
log_error("Couldn't read 'max_recovery_rate' for "
|
||||
"segment %s of logical volume %s.",
|
||||
dm_config_parent_name(sn), seg->lv->name);
|
||||
return 0;
|
||||
for (i = 0; i < DM_ARRAY_SIZE(raid_attr_import); i++, aip++) {
|
||||
if (dm_config_has_node(sn, aip->name)) {
|
||||
if (!dm_config_get_uint32(sn, aip->name, aip->var)) {
|
||||
log_error("Couldn't read '%s' for segment %s of logical volume %s.",
|
||||
aip->name, dm_config_parent_name(sn), seg->lv->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!dm_config_get_list(sn, "raids", &cv)) {
|
||||
log_error("Couldn't find RAID array for "
|
||||
"segment %s of logical volume %s.",
|
||||
@@ -162,7 +141,7 @@ static int _raid_text_import(struct lv_segment *seg,
|
||||
}
|
||||
|
||||
if (!_raid_text_import_areas(seg, sn, cv)) {
|
||||
log_error("Failed to import RAID images");
|
||||
log_error("Failed to import RAID component pairs.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -242,7 +221,7 @@ static int _raid_add_target_line(struct dev_manager *dm __attribute__((unused)),
|
||||
/* RAID 4/5/6 */
|
||||
params.mirrors = 1;
|
||||
params.stripes = seg->area_count - seg->segtype->parity_devs;
|
||||
} else if (strcmp(seg->segtype->name, SEG_TYPE_NAME_RAID10)) {
|
||||
} else if (seg_is_raid10(seg)) {
|
||||
/* RAID 10 only supports 2 mirrors now */
|
||||
params.mirrors = 2;
|
||||
params.stripes = seg->area_count / 2;
|
||||
@@ -301,8 +280,8 @@ static int _raid_target_percent(void **target_state,
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (!pos || (sscanf(pos, FMTu64 "/" FMTu64 "%n",
|
||||
&numerator, &denominator, &i) != 2)) {
|
||||
if (!pos || (sscanf(pos, FMTu64 "/" FMTu64 "%n", &numerator, &denominator, &i) != 2) ||
|
||||
!denominator) {
|
||||
log_error("Failed to parse %s status fraction: %s",
|
||||
(seg) ? seg->segtype->name : "segment", params);
|
||||
return 0;
|
||||
@@ -331,6 +310,7 @@ static int _raid_target_present(struct cmd_context *cmd,
|
||||
const char *feature;
|
||||
} _features[] = {
|
||||
{ 1, 3, RAID_FEATURE_RAID10, SEG_TYPE_NAME_RAID10 },
|
||||
{ 1, 7, RAID_FEATURE_RAID0, SEG_TYPE_NAME_RAID0 },
|
||||
};
|
||||
|
||||
static int _raid_checked = 0;
|
||||
@@ -434,25 +414,25 @@ static struct segtype_handler _raid_ops = {
|
||||
static const struct raid_type {
|
||||
const char name[12];
|
||||
unsigned parity;
|
||||
int extra_flags;
|
||||
uint64_t extra_flags;
|
||||
} _raid_types[] = {
|
||||
{ SEG_TYPE_NAME_RAID1, 0, SEG_AREAS_MIRRORED },
|
||||
{ SEG_TYPE_NAME_RAID10, 0, SEG_AREAS_MIRRORED },
|
||||
{ SEG_TYPE_NAME_RAID4, 1 },
|
||||
{ SEG_TYPE_NAME_RAID5, 1 },
|
||||
{ SEG_TYPE_NAME_RAID5_LA, 1 },
|
||||
{ SEG_TYPE_NAME_RAID5_LS, 1 },
|
||||
{ SEG_TYPE_NAME_RAID5_RA, 1 },
|
||||
{ SEG_TYPE_NAME_RAID5_RS, 1 },
|
||||
{ SEG_TYPE_NAME_RAID6, 2 },
|
||||
{ SEG_TYPE_NAME_RAID6_NC, 2 },
|
||||
{ SEG_TYPE_NAME_RAID6_NR, 2 },
|
||||
{ SEG_TYPE_NAME_RAID6_ZR, 2 }
|
||||
{ SEG_TYPE_NAME_RAID1, 0, SEG_RAID1 | SEG_AREAS_MIRRORED },
|
||||
{ SEG_TYPE_NAME_RAID10, 0, SEG_RAID10 | SEG_AREAS_MIRRORED },
|
||||
{ SEG_TYPE_NAME_RAID4, 1, SEG_RAID4 },
|
||||
{ SEG_TYPE_NAME_RAID5, 1, SEG_RAID5 },
|
||||
{ SEG_TYPE_NAME_RAID5_LA, 1, SEG_RAID5_LA },
|
||||
{ SEG_TYPE_NAME_RAID5_LS, 1, SEG_RAID5_LS },
|
||||
{ SEG_TYPE_NAME_RAID5_RA, 1, SEG_RAID5_RA },
|
||||
{ SEG_TYPE_NAME_RAID5_RS, 1, SEG_RAID5_RS },
|
||||
{ SEG_TYPE_NAME_RAID6, 2, SEG_RAID6 },
|
||||
{ SEG_TYPE_NAME_RAID6_NC, 2, SEG_RAID6_NC },
|
||||
{ SEG_TYPE_NAME_RAID6_NR, 2, SEG_RAID6_NR },
|
||||
{ SEG_TYPE_NAME_RAID6_ZR, 2, SEG_RAID6_ZR }
|
||||
};
|
||||
|
||||
static struct segment_type *_init_raid_segtype(struct cmd_context *cmd,
|
||||
const struct raid_type *rt,
|
||||
int monitored)
|
||||
uint64_t monitored)
|
||||
{
|
||||
struct segment_type *segtype = dm_zalloc(sizeof(*segtype));
|
||||
|
||||
@@ -482,7 +462,7 @@ int init_multiple_segtypes(struct cmd_context *cmd, struct segtype_library *segl
|
||||
{
|
||||
struct segment_type *segtype;
|
||||
unsigned i;
|
||||
int monitored = 0;
|
||||
uint64_t monitored = 0;
|
||||
|
||||
#ifdef DEVMAPPER_SUPPORT
|
||||
# ifdef DMEVENTD
|
||||
|
||||
@@ -63,6 +63,7 @@ FIELD(LVS, lv, SIZ, "LSize", size, 5, size64, lv_size, "Size of LV in current un
|
||||
FIELD(LVS, lv, SIZ, "MSize", lvid, 6, lvmetadatasize, lv_metadata_size, "For thin and cache pools, the size of the LV that holds the metadata.", 0)
|
||||
FIELD(LVS, lv, NUM, "#Seg", lvid, 4, lvsegcount, seg_count, "Number of segments in LV.", 0)
|
||||
FIELD(LVS, lv, STR, "Origin", lvid, 6, origin, origin, "For snapshots, the origin device of this LV.", 0)
|
||||
FIELD(LVS, lv, STR, "Origin UUID", lvid, 38, originuuid, origin_uuid, "For snapshots, the UUID of origin device of this LV.", 0)
|
||||
FIELD(LVS, lv, SIZ, "OSize", lvid, 5, originsize, origin_size, "For snapshots, the size of the origin device of this LV.", 0)
|
||||
FIELD(LVS, lv, STR_LIST, "Ancestors", lvid, 12, lvancestors, lv_ancestors, "Ancestors of this LV.", 0)
|
||||
FIELD(LVS, lv, STR_LIST, "Descendants", lvid, 12, lvdescendants, lv_descendants, "Descendants of this LV.", 0)
|
||||
@@ -77,11 +78,17 @@ FIELD(LVS, lv, NUM, "WBehind", lvid, 7, raidwritebehind, raid_write_behind, "For
|
||||
FIELD(LVS, lv, NUM, "MinSync", lvid, 7, raidminrecoveryrate, raid_min_recovery_rate, "For RAID1, the minimum recovery I/O load in kiB/sec/disk.", 0)
|
||||
FIELD(LVS, lv, NUM, "MaxSync", lvid, 7, raidmaxrecoveryrate, raid_max_recovery_rate, "For RAID1, the maximum recovery I/O load in kiB/sec/disk.", 0)
|
||||
FIELD(LVS, lv, STR, "Move", lvid, 4, movepv, move_pv, "For pvmove, Source PV of temporary LV created by pvmove.", 0)
|
||||
FIELD(LVS, lv, STR, "Move UUID", lvid, 38, movepvuuid, move_pv_uuid, "For pvmove, the UUID of Source PV of temporary LV created by pvmove.", 0)
|
||||
FIELD(LVS, lv, STR, "Convert", lvid, 7, convertlv, convert_lv, "For lvconvert, Name of temporary LV created by lvconvert.", 0)
|
||||
FIELD(LVS, lv, STR, "Convert", lvid, 38, convertlvuuid, convert_lv_uuid, "For lvconvert, UUID of temporary LV created by lvconvert.", 0)
|
||||
FIELD(LVS, lv, STR, "Log", lvid, 3, loglv, mirror_log, "For mirrors, the LV holding the synchronisation log.", 0)
|
||||
FIELD(LVS, lv, STR, "Log UUID", lvid, 38, loglvuuid, mirror_log_uuid, "For mirrors, the UUID of the LV holding the synchronisation log.", 0)
|
||||
FIELD(LVS, lv, STR, "Data", lvid, 4, datalv, data_lv, "For thin and cache pools, the LV holding the associated data.", 0)
|
||||
FIELD(LVS, lv, STR, "Data UUID", lvid, 38, datalvuuid, data_lv_uuid, "For thin and cache pools, the UUID of the LV holding the associated data.", 0)
|
||||
FIELD(LVS, lv, STR, "Meta", lvid, 4, metadatalv, metadata_lv, "For thin and cache pools, the LV holding the associated metadata.", 0)
|
||||
FIELD(LVS, lv, STR, "Meta UUID", lvid, 38, metadatalvuuid, metadata_lv_uuid, "For thin and cache pools, the UUID of the LV holding the associated metadata.", 0)
|
||||
FIELD(LVS, lv, STR, "Pool", lvid, 4, poollv, pool_lv, "For thin volumes, the thin pool LV for this volume.", 0)
|
||||
FIELD(LVS, lv, STR, "Pool UUID", lvid, 38, poollvuuid, pool_lv_uuid, "For thin volumes, the UUID of the thin pool LV for this volume.", 0)
|
||||
FIELD(LVS, lv, STR_LIST, "LV Tags", tags, 7, tags, lv_tags, "Tags, if any.", 0)
|
||||
FIELD(LVS, lv, STR, "LProfile", lvid, 8, lvprofile, lv_profile, "Configuration profile attached to this LV.", 0)
|
||||
FIELD(LVS, lv, STR, "Lock Args", lvid, 9, lvlockargs, lv_lockargs, "Lock args of the LV used by lvmlockd.", 0)
|
||||
@@ -151,7 +158,8 @@ FIELD(VGS, vg, NUM, "#Ext", extent_count, 4, uint32, vg_extent_count, "Total num
|
||||
FIELD(VGS, vg, NUM, "Free", free_count, 4, uint32, vg_free_count, "Total number of unallocated Physical Extents.", 0)
|
||||
FIELD(VGS, vg, NUM, "MaxLV", max_lv, 5, uint32, max_lv, "Maximum number of LVs allowed in VG or 0 if unlimited.", 0)
|
||||
FIELD(VGS, vg, NUM, "MaxPV", max_pv, 5, uint32, max_pv, "Maximum number of PVs allowed in VG or 0 if unlimited.", 0)
|
||||
FIELD(VGS, vg, NUM, "#PV", pv_count, 3, uint32, pv_count, "Number of PVs.", 0)
|
||||
FIELD(VGS, vg, NUM, "#PV", pv_count, 3, uint32, pv_count, "Number of PVs in VG.", 0)
|
||||
FIELD(VGS, vg, NUM, "#PV Missing", cmd, 11, vgmissingpvcount, vg_missing_pv_count, "Number of PVs in VG which are missing.", 0)
|
||||
FIELD(VGS, vg, NUM, "#LV", cmd, 3, lvcount, lv_count, "Number of LVs.", 0)
|
||||
FIELD(VGS, vg, NUM, "#SN", cmd, 3, snapcount, snap_count, "Number of snapshots.", 0)
|
||||
FIELD(VGS, vg, NUM, "Seq", seqno, 3, uint32, vg_seqno, "Revision number of internal metadata. Incremented whenever it changes.", 0)
|
||||
@@ -183,7 +191,9 @@ FIELD(SEGS, seg, SIZ, "SSize", list, 5, segsize, seg_size, "Size of segment in c
|
||||
FIELD(SEGS, seg, SIZ, "SSize", list, 5, segsizepe, seg_size_pe, "Size of segment in physical extents.", 0)
|
||||
FIELD(SEGS, seg, STR_LIST, "Seg Tags", tags, 8, tags, seg_tags, "Tags, if any.", 0)
|
||||
FIELD(SEGS, seg, STR, "PE Ranges", list, 9, peranges, seg_pe_ranges, "Ranges of Physical Extents of underlying devices in command line format.", 0)
|
||||
FIELD(SEGS, seg, STR, "Metadata LE Ranges", list, 18, metadataleranges, seg_metadata_le_ranges, "Ranges of Logical Extents of underlying metadata devices in command line format.", 0)
|
||||
FIELD(SEGS, seg, STR, "Devices", list, 7, devices, devices, "Underlying devices used with starting extent numbers.", 0)
|
||||
FIELD(SEGS, seg, STR, "Metadata Devs", list, 13, metadatadevices, metadata_devices, "Underlying metadata devices used with starting extent numbers.", 0)
|
||||
FIELD(SEGS, seg, STR, "Monitor", list, 7, segmonitor, seg_monitor, "Dmeventd monitoring status of the segment.", 0)
|
||||
FIELD(SEGS, seg, STR, "Cache Policy", list, 12, cache_policy, cache_policy, "The cache policy (cached segments only).", 0)
|
||||
FIELD(SEGS, seg, STR_LIST, "Cache Settings", list, 14, cache_settings, cache_settings, "Cache settings/parameters (cached segments only).", 0)
|
||||
|
||||
@@ -149,11 +149,11 @@ static dm_percent_t _metadata_percent(const struct logical_volume *lv)
|
||||
/* PV */
|
||||
GET_PV_STR_PROPERTY_FN(pv_fmt, pv_fmt_dup(pv))
|
||||
#define _pv_fmt_set prop_not_implemented_set
|
||||
GET_PV_STR_PROPERTY_FN(pv_uuid, pv_uuid_dup(pv))
|
||||
GET_PV_STR_PROPERTY_FN(pv_uuid, pv_uuid_dup(pv->vg->vgmem, pv))
|
||||
#define _pv_uuid_set prop_not_implemented_set
|
||||
GET_PV_NUM_PROPERTY_FN(dev_size, SECTOR_SIZE * pv_dev_size(pv))
|
||||
#define _dev_size_set prop_not_implemented_set
|
||||
GET_PV_STR_PROPERTY_FN(pv_name, pv_name_dup(pv))
|
||||
GET_PV_STR_PROPERTY_FN(pv_name, pv_name_dup(pv->vg->vgmem, pv))
|
||||
#define _pv_name_set prop_not_implemented_set
|
||||
GET_PV_NUM_PROPERTY_FN(pv_mda_free, SECTOR_SIZE * pv_mda_free(pv))
|
||||
#define _pv_mda_free_set prop_not_implemented_set
|
||||
@@ -264,7 +264,7 @@ GET_PV_NUM_PROPERTY_FN(pv_ba_size, SECTOR_SIZE * pv->ba_size)
|
||||
#define _cache_write_misses_get prop_not_implemented_get
|
||||
|
||||
/* LV */
|
||||
GET_LV_STR_PROPERTY_FN(lv_uuid, lv_uuid_dup(lv))
|
||||
GET_LV_STR_PROPERTY_FN(lv_uuid, lv_uuid_dup(lv->vg->vgmem, lv))
|
||||
#define _lv_uuid_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(lv_name, lv_name_dup(lv->vg->vgmem, lv))
|
||||
#define _lv_name_set prop_not_implemented_set
|
||||
@@ -298,6 +298,8 @@ GET_LV_NUM_PROPERTY_FN(seg_count, dm_list_size(&lv->segments))
|
||||
#define _seg_count_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(origin, lv_origin_dup(lv->vg->vgmem, lv))
|
||||
#define _origin_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(origin_uuid, lv_origin_uuid_dup(lv->vg->vgmem, lv))
|
||||
#define _origin_uuid_set prop_not_implemented_set
|
||||
GET_LV_NUM_PROPERTY_FN(origin_size, (SECTOR_SIZE * lv_origin_size(lv)))
|
||||
#define _origin_size_set prop_not_implemented_set
|
||||
#define _lv_ancestors_set prop_not_implemented_set
|
||||
@@ -322,20 +324,32 @@ GET_LV_STR_PROPERTY_FN(raid_sync_action, _raidsyncaction(lv))
|
||||
#define _raid_sync_action_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(move_pv, lv_move_pv_dup(lv->vg->vgmem, lv))
|
||||
#define _move_pv_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(move_pv_uuid, lv_move_pv_uuid_dup(lv->vg->vgmem, lv))
|
||||
#define _move_pv_uuid_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(convert_lv, lv_convert_lv_dup(lv->vg->vgmem, lv))
|
||||
#define _convert_lv_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(convert_lv_uuid, lv_convert_lv_uuid_dup(lv->vg->vgmem, lv))
|
||||
#define _convert_lv_uuid_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(lv_tags, lv_tags_dup(lv))
|
||||
#define _lv_tags_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(mirror_log, lv_mirror_log_dup(lv->vg->vgmem, lv))
|
||||
#define _mirror_log_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(mirror_log_uuid, lv_mirror_log_uuid_dup(lv->vg->vgmem, lv))
|
||||
#define _mirror_log_uuid_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(lv_modules, lv_modules_dup(lv->vg->vgmem, lv))
|
||||
#define _lv_modules_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(data_lv, lv_data_lv_dup(lv->vg->vgmem, lv))
|
||||
#define _data_lv_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(data_lv_uuid, lv_data_lv_uuid_dup(lv->vg->vgmem, lv))
|
||||
#define _data_lv_uuid_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(metadata_lv, lv_metadata_lv_dup(lv->vg->vgmem, lv))
|
||||
#define _metadata_lv_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(metadata_lv_uuid, lv_metadata_lv_uuid_dup(lv->vg->vgmem, lv))
|
||||
#define _metadata_lv_uuid_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(pool_lv, lv_pool_lv_dup(lv->vg->vgmem, lv))
|
||||
#define _pool_lv_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(pool_lv_uuid, lv_pool_lv_uuid_dup(lv->vg->vgmem, lv))
|
||||
#define _pool_lv_uuid_set prop_not_implemented_set
|
||||
GET_LV_NUM_PROPERTY_FN(data_percent, _data_percent(lv))
|
||||
#define _data_percent_set prop_not_implemented_set
|
||||
GET_LV_NUM_PROPERTY_FN(metadata_percent, _metadata_percent(lv))
|
||||
@@ -406,6 +420,8 @@ GET_VG_NUM_PROPERTY_FN(vg_mda_copies, (vg_mda_copies(vg)))
|
||||
SET_VG_NUM_PROPERTY_FN(vg_mda_copies, vg_set_mda_copies)
|
||||
GET_VG_STR_PROPERTY_FN(vg_profile, vg_profile_dup(vg))
|
||||
#define _vg_profile_set prop_not_implemented_set
|
||||
GET_VG_NUM_PROPERTY_FN(vg_missing_pv_count, vg_missing_pv_count(vg))
|
||||
#define _vg_missing_pv_count_set prop_not_implemented_set
|
||||
|
||||
/* LVSEG */
|
||||
GET_LVSEG_STR_PROPERTY_FN(segtype, lvseg_segtype_dup(lvseg->lv->vg->vgmem, lvseg))
|
||||
@@ -449,8 +465,13 @@ GET_LVSEG_STR_PROPERTY_FN(seg_tags, lvseg_tags_dup(lvseg))
|
||||
GET_LVSEG_STR_PROPERTY_FN(seg_pe_ranges,
|
||||
lvseg_seg_pe_ranges(lvseg->lv->vg->vgmem, lvseg))
|
||||
#define _seg_pe_ranges_set prop_not_implemented_set
|
||||
GET_LVSEG_STR_PROPERTY_FN(seg_metadata_le_ranges,
|
||||
lvseg_seg_metadata_le_ranges(lvseg->lv->vg->vgmem, lvseg))
|
||||
#define _seg_metadata_le_ranges_set prop_not_implemented_set
|
||||
GET_LVSEG_STR_PROPERTY_FN(devices, lvseg_devices(lvseg->lv->vg->vgmem, lvseg))
|
||||
#define _devices_set prop_not_implemented_set
|
||||
GET_LVSEG_STR_PROPERTY_FN(metadata_devices, lvseg_metadata_devices(lvseg->lv->vg->vgmem, lvseg))
|
||||
#define _metadata_devices_set prop_not_implemented_set
|
||||
GET_LVSEG_STR_PROPERTY_FN(seg_monitor, lvseg_monitor_dup(lvseg->lv->vg->vgmem, lvseg))
|
||||
#define _seg_monitor_set prop_not_implemented_set
|
||||
|
||||
|
||||
@@ -1271,6 +1271,18 @@ static int _chars_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((
|
||||
return dm_report_field_string(rh, field, (const char * const *) &data);
|
||||
}
|
||||
|
||||
static int _uuid_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)))
|
||||
{
|
||||
char *repstr;
|
||||
|
||||
if (!(repstr = id_format_and_copy(mem, data)))
|
||||
return_0;
|
||||
|
||||
return _field_set_value(field, repstr, NULL);
|
||||
}
|
||||
|
||||
static int _dev_name_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)))
|
||||
@@ -1292,6 +1304,18 @@ static int _devices_disp(struct dm_report *rh __attribute__((unused)), struct dm
|
||||
return _field_set_value(field, str, NULL);
|
||||
}
|
||||
|
||||
static int _metadatadevices_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)))
|
||||
{
|
||||
char *str;
|
||||
|
||||
if (!(str = lvseg_metadata_devices(mem, (const struct lv_segment *) data)))
|
||||
return_0;
|
||||
|
||||
return _field_set_value(field, str, NULL);
|
||||
}
|
||||
|
||||
static int _peranges_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)))
|
||||
@@ -1304,6 +1328,18 @@ static int _peranges_disp(struct dm_report *rh __attribute__((unused)), struct d
|
||||
return _field_set_value(field, str, NULL);
|
||||
}
|
||||
|
||||
static int _metadataleranges_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)))
|
||||
{
|
||||
char *str;
|
||||
|
||||
if (!(str = lvseg_seg_metadata_le_ranges(mem, (const struct lv_segment *) data)))
|
||||
return_0;
|
||||
|
||||
return _field_set_value(field, str, NULL);
|
||||
}
|
||||
|
||||
static int _tags_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private)
|
||||
@@ -1543,17 +1579,37 @@ static int _segtype_disp(struct dm_report *rh __attribute__((unused)),
|
||||
return _field_set_value(field, name, NULL);
|
||||
}
|
||||
|
||||
static int _do_loglv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)),
|
||||
int uuid)
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
const char *repstr = NULL;
|
||||
|
||||
if (uuid)
|
||||
repstr = lv_mirror_log_uuid_dup(mem, lv);
|
||||
else
|
||||
repstr = lv_mirror_log_dup(mem, lv);
|
||||
|
||||
if (repstr)
|
||||
return dm_report_field_string(rh, field, &repstr);
|
||||
|
||||
return _field_set_value(field, "", NULL);
|
||||
}
|
||||
|
||||
static int _loglv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)))
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
const char *name;
|
||||
return _do_loglv_disp(rh, mem, field, data, private, 0);
|
||||
}
|
||||
|
||||
if ((name = lv_mirror_log_dup(mem, lv)))
|
||||
return dm_report_field_string(rh, field, &name);
|
||||
|
||||
return _field_set_value(field, "", NULL);
|
||||
static int _loglvuuid_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)))
|
||||
{
|
||||
return _do_loglv_disp(rh, mem, field, data, private, 1);
|
||||
}
|
||||
|
||||
static int _lvname_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
@@ -1612,15 +1668,52 @@ static int _lvparent_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
return _field_set_value(field, repstr, NULL);
|
||||
}
|
||||
|
||||
static int _datalv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)))
|
||||
static int _do_datalv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)),
|
||||
int uuid)
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
const struct lv_segment *seg = (lv_is_pool(lv)) ? first_seg(lv) : NULL;
|
||||
|
||||
if (seg)
|
||||
return _lvname_disp(rh, mem, field, seg_lv(seg, 0), private);
|
||||
if (seg) {
|
||||
if (uuid)
|
||||
return _uuid_disp(rh, mem, field, &seg_lv(seg, 0)->lvid.id[1], private);
|
||||
else
|
||||
return _lvname_disp(rh, mem, field, seg_lv(seg, 0), private);
|
||||
}
|
||||
|
||||
return _field_set_value(field, "", NULL);
|
||||
}
|
||||
|
||||
static int _datalv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)))
|
||||
{
|
||||
return _do_datalv_disp(rh, mem, field, data, private, 0);
|
||||
}
|
||||
|
||||
static int _datalvuuid_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)))
|
||||
{
|
||||
return _do_datalv_disp(rh, mem, field, data, private, 1);
|
||||
}
|
||||
|
||||
static int _do_metadatalv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)),
|
||||
int uuid)
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
const struct lv_segment *seg = (lv_is_pool(lv)) ? first_seg(lv) : NULL;
|
||||
|
||||
if (seg) {
|
||||
if (uuid)
|
||||
return _uuid_disp(rh, mem, field, &seg->metadata_lv->lvid.id[1], private);
|
||||
else
|
||||
return _lvname_disp(rh, mem, field, seg->metadata_lv, private);
|
||||
}
|
||||
|
||||
return _field_set_value(field, "", NULL);
|
||||
}
|
||||
@@ -1629,11 +1722,31 @@ static int _metadatalv_disp(struct dm_report *rh, struct dm_pool *mem __attribut
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)))
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
const struct lv_segment *seg = (lv_is_pool(lv)) ? first_seg(lv) : NULL;
|
||||
return _do_metadatalv_disp(rh, mem, field, data, private, 0);
|
||||
}
|
||||
|
||||
if (seg)
|
||||
return _lvname_disp(rh, mem, field, seg->metadata_lv, private);
|
||||
static int _metadatalvuuid_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)))
|
||||
{
|
||||
return _do_metadatalv_disp(rh, mem, field, data, private, 1);
|
||||
}
|
||||
|
||||
static int _do_poollv_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private,
|
||||
int uuid)
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
struct lv_segment *seg = (lv_is_thin_volume(lv) || lv_is_cache(lv)) ?
|
||||
first_seg(lv) : NULL;
|
||||
|
||||
if (seg) {
|
||||
if (uuid)
|
||||
return _uuid_disp(rh, mem, field, &seg->pool_lv->lvid.id[1], private);
|
||||
else
|
||||
return _lvname_disp(rh, mem, field, seg->pool_lv, private);
|
||||
}
|
||||
|
||||
return _field_set_value(field, "", NULL);
|
||||
}
|
||||
@@ -1642,14 +1755,14 @@ static int _poollv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__(
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)))
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
struct lv_segment *seg = (lv_is_thin_volume(lv) || lv_is_cache(lv)) ?
|
||||
first_seg(lv) : NULL;
|
||||
return _do_poollv_disp(rh, mem, field, data, private, 0);
|
||||
}
|
||||
|
||||
if (seg)
|
||||
return _lvname_disp(rh, mem, field, seg->pool_lv, private);
|
||||
|
||||
return _field_set_value(field, "", NULL);
|
||||
static int _poollvuuid_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)))
|
||||
{
|
||||
return _do_poollv_disp(rh, mem, field, data, private, 1);
|
||||
}
|
||||
|
||||
static int _lvpath_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
@@ -1678,26 +1791,44 @@ static int _lvdmpath_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
return _field_set_value(field, repstr, NULL);
|
||||
}
|
||||
|
||||
static int _do_origin_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private,
|
||||
int uuid)
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
const struct lv_segment *seg = first_seg(lv);
|
||||
struct logical_volume *origin;
|
||||
|
||||
if (lv_is_cow(lv))
|
||||
origin = origin_from_cow(lv);
|
||||
else if (lv_is_cache(lv) && !lv_is_pending_delete(lv))
|
||||
origin = seg_lv(seg, 0);
|
||||
else if (lv_is_thin_volume(lv) && first_seg(lv)->origin)
|
||||
origin = first_seg(lv)->origin;
|
||||
else if (lv_is_thin_volume(lv) && first_seg(lv)->external_lv)
|
||||
origin = first_seg(lv)->external_lv;
|
||||
else
|
||||
return _field_set_value(field, "", NULL);
|
||||
|
||||
if (uuid)
|
||||
return _uuid_disp(rh, mem, field, &origin->lvid.id[1], private);
|
||||
else
|
||||
return _lvname_disp(rh, mem, field, origin, private);
|
||||
}
|
||||
|
||||
static int _origin_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private)
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
const struct lv_segment *seg = first_seg(lv);
|
||||
return _do_origin_disp(rh, mem, field, data, private, 0);
|
||||
}
|
||||
|
||||
if (lv_is_cow(lv))
|
||||
return _lvname_disp(rh, mem, field, origin_from_cow(lv), private);
|
||||
|
||||
if (lv_is_cache(lv) && !lv_is_pending_delete(lv))
|
||||
return _lvname_disp(rh, mem, field, seg_lv(seg, 0), private);
|
||||
|
||||
if (lv_is_thin_volume(lv) && first_seg(lv)->origin)
|
||||
return _lvname_disp(rh, mem, field, first_seg(lv)->origin, private);
|
||||
|
||||
if (lv_is_thin_volume(lv) && first_seg(lv)->external_lv)
|
||||
return _lvname_disp(rh, mem, field, first_seg(lv)->external_lv, private);
|
||||
|
||||
return _field_set_value(field, "", NULL);
|
||||
static int _originuuid_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private)
|
||||
{
|
||||
return _do_origin_disp(rh, mem, field, data, private, 1);
|
||||
}
|
||||
|
||||
static int _find_ancestors(struct _str_list_append_baton *ancestors,
|
||||
@@ -1800,15 +1931,54 @@ static int _lvdescendants_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
return _field_set_string_list(rh, field, descendants.result, private, 0);
|
||||
}
|
||||
|
||||
static int _do_movepv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)),
|
||||
int uuid)
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
const char *repstr;
|
||||
|
||||
if (uuid)
|
||||
repstr = lv_move_pv_uuid_dup(mem, lv);
|
||||
else
|
||||
repstr = lv_move_pv_dup(mem, lv);
|
||||
|
||||
if (repstr)
|
||||
return dm_report_field_string(rh, field, &repstr);
|
||||
|
||||
return _field_set_value(field, "", NULL);
|
||||
}
|
||||
|
||||
static int _movepv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)))
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
const char *name;
|
||||
return _do_movepv_disp(rh, mem, field, data, private, 0);
|
||||
}
|
||||
|
||||
if ((name = lv_move_pv_dup(mem, lv)))
|
||||
return dm_report_field_string(rh, field, &name);
|
||||
static int _movepvuuid_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)))
|
||||
{
|
||||
return _do_movepv_disp(rh, mem, field, data, private, 1);
|
||||
}
|
||||
|
||||
static int _do_convertlv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)),
|
||||
int uuid)
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
const char *repstr;
|
||||
|
||||
if (uuid)
|
||||
repstr = lv_convert_lv_uuid_dup(mem, lv);
|
||||
else
|
||||
repstr = lv_convert_lv_dup(mem, lv);
|
||||
|
||||
if (repstr)
|
||||
return dm_report_field_string(rh, field, &repstr);
|
||||
|
||||
return _field_set_value(field, "", NULL);
|
||||
}
|
||||
@@ -1817,13 +1987,14 @@ static int _convertlv_disp(struct dm_report *rh, struct dm_pool *mem __attribute
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)))
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
const char *name;
|
||||
return _do_convertlv_disp(rh, mem, field, data, private, 0);
|
||||
}
|
||||
|
||||
if ((name = lv_convert_lv_dup(mem, lv)))
|
||||
return dm_report_field_string(rh, field, &name);
|
||||
|
||||
return _field_set_value(field, "", NULL);
|
||||
static int _convertlvuuid_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)))
|
||||
{
|
||||
return _do_convertlv_disp(rh, mem, field, data, private, 1);
|
||||
}
|
||||
|
||||
static int _size32_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
|
||||
@@ -2187,30 +2358,16 @@ static int _vglockargs_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
return _string_disp(rh, mem, field, &repstr, private);
|
||||
}
|
||||
|
||||
static int _uuid_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)))
|
||||
{
|
||||
char *repstr;
|
||||
|
||||
if (!(repstr = id_format_and_copy(mem, data)))
|
||||
return_0;
|
||||
|
||||
return _field_set_value(field, repstr, NULL);
|
||||
}
|
||||
|
||||
static int _pvuuid_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)))
|
||||
{
|
||||
const struct label *label = (const struct label *) data;
|
||||
const char *repstr = "";
|
||||
|
||||
if (label->dev &&
|
||||
!(repstr = id_format_and_copy(mem, (const struct id *) label->dev->pvid)))
|
||||
return_0;
|
||||
if (!label->dev)
|
||||
return _field_set_value(field, "", NULL);
|
||||
|
||||
return _field_set_value(field, repstr, NULL);
|
||||
return _uuid_disp(rh, mem, field, label->dev->pvid, private);
|
||||
}
|
||||
|
||||
static int _pvmdas_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
@@ -2281,6 +2438,17 @@ static int _vgprofile_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
return _field_set_value(field, "", NULL);
|
||||
}
|
||||
|
||||
static int _vgmissingpvcount_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private)
|
||||
{
|
||||
const struct volume_group *vg = (const struct volume_group *) data;
|
||||
uint32_t count = vg_missing_pv_count(vg);
|
||||
|
||||
return _uint32_disp(rh, mem, field, &count, private);
|
||||
}
|
||||
|
||||
|
||||
static int _pvmdafree_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private)
|
||||
@@ -3228,6 +3396,21 @@ void *report_init_for_selection(struct cmd_context *cmd,
|
||||
cmd);
|
||||
}
|
||||
|
||||
const char *report_get_field_prefix(report_type_t report_type_id)
|
||||
{
|
||||
const struct dm_report_object_type *report_types, *report_type;
|
||||
|
||||
report_types = report_type_id & DEVTYPES ? _devtypes_report_types
|
||||
: _report_types;
|
||||
|
||||
for (report_type = report_types; report_type->id; report_type++) {
|
||||
if (report_type_id & report_type->id)
|
||||
return report_type->prefix;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a row of data for an object
|
||||
*/
|
||||
|
||||
@@ -71,6 +71,7 @@ void *report_init(struct cmd_context *cmd, const char *format, const char *keys,
|
||||
int quoted, int columns_as_rows, const char *selection);
|
||||
void *report_init_for_selection(struct cmd_context *cmd, report_type_t *report_type,
|
||||
const char *selection);
|
||||
const char *report_get_field_prefix(report_type_t report_type);
|
||||
int report_for_selection(struct cmd_context *cmd,
|
||||
struct selection_handle *sh,
|
||||
struct physical_volume *pv,
|
||||
|
||||
@@ -259,7 +259,7 @@ struct segment_type *init_segtype(struct cmd_context *cmd)
|
||||
return_NULL;
|
||||
|
||||
segtype->ops = &_snapshot_ops;
|
||||
segtype->name = "snapshot";
|
||||
segtype->name = SEG_TYPE_NAME_SNAPSHOT;
|
||||
segtype->flags = SEG_SNAPSHOT | SEG_CANNOT_BE_ZEROED | SEG_ONLY_EXCLUSIVE;
|
||||
|
||||
#ifdef DEVMAPPER_SUPPORT
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
static const char *_striped_name(const struct lv_segment *seg)
|
||||
{
|
||||
return (seg->area_count == 1) ? "linear" : seg->segtype->name;
|
||||
return (seg->area_count == 1) ? SEG_TYPE_NAME_LINEAR : seg->segtype->name;
|
||||
}
|
||||
|
||||
static void _striped_display(const struct lv_segment *seg)
|
||||
@@ -229,7 +229,7 @@ struct segment_type *init_striped_segtype(struct cmd_context *cmd)
|
||||
return_NULL;
|
||||
|
||||
segtype->ops = &_striped_ops;
|
||||
segtype->name = "striped";
|
||||
segtype->name = SEG_TYPE_NAME_STRIPED;
|
||||
segtype->flags =
|
||||
SEG_CAN_SPLIT | SEG_AREAS_STRIPED | SEG_FORMAT1_SUPPORT;
|
||||
|
||||
|
||||
@@ -118,10 +118,6 @@ static int _thin_pool_text_import(struct lv_segment *seg,
|
||||
else if (!set_pool_discards(&seg->discards, discards_str))
|
||||
return SEG_LOG_ERROR("Discards option unsupported for");
|
||||
|
||||
if (dm_config_has_node(sn, "low_water_mark") &&
|
||||
!dm_config_get_uint64(sn, "low_water_mark", &seg->low_water_mark))
|
||||
return SEG_LOG_ERROR("Could not read low_water_mark");
|
||||
|
||||
if ((seg->chunk_size < DM_THIN_MIN_DATA_BLOCK_SIZE) ||
|
||||
(seg->chunk_size > DM_THIN_MAX_DATA_BLOCK_SIZE))
|
||||
return SEG_LOG_ERROR("Unsupported value %u for chunk_size",
|
||||
@@ -169,9 +165,6 @@ static int _thin_pool_text_export(const struct lv_segment *seg, struct formatter
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (seg->low_water_mark)
|
||||
outf(f, "low_water_mark = %" PRIu64, seg->low_water_mark);
|
||||
|
||||
if (seg->zero_new_blocks)
|
||||
outf(f, "zero_new_blocks = 1");
|
||||
|
||||
@@ -266,6 +259,8 @@ static int _thin_pool_add_target_line(struct dev_manager *dm,
|
||||
struct lvinfo info;
|
||||
uint64_t transaction_id = 0;
|
||||
unsigned attr;
|
||||
uint64_t low_water_mark;
|
||||
int threshold;
|
||||
|
||||
if (!_thin_target_present(cmd, NULL, &attr))
|
||||
return_0;
|
||||
@@ -277,27 +272,37 @@ static int _thin_pool_add_target_line(struct dev_manager *dm,
|
||||
|
||||
if (!(attr & THIN_FEATURE_BLOCK_SIZE) &&
|
||||
(seg->chunk_size & (seg->chunk_size - 1))) {
|
||||
log_error("Thin pool target does not support %uKiB chunk size "
|
||||
"(needs kernel >= 3.6).", seg->chunk_size / 2);
|
||||
log_error("Thin pool target does not support %s chunk size (needs"
|
||||
" kernel >= 3.6).", display_size(cmd, seg->chunk_size));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(metadata_dlid = build_dm_uuid(mem, seg->metadata_lv, NULL))) {
|
||||
log_error("Failed to build uuid for metadata LV %s.",
|
||||
seg->metadata_lv->name);
|
||||
display_lvname(seg->metadata_lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(pool_dlid = build_dm_uuid(mem, seg_lv(seg, 0), NULL))) {
|
||||
log_error("Failed to build uuid for pool LV %s.",
|
||||
seg_lv(seg, 0)->name);
|
||||
display_lvname(seg_lv(seg, 0)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
threshold = find_config_tree_int(seg->lv->vg->cmd,
|
||||
activation_thin_pool_autoextend_threshold_CFG,
|
||||
lv_config_profile(seg->lv));
|
||||
if (threshold < 50)
|
||||
threshold = 50;
|
||||
if (threshold < 100)
|
||||
low_water_mark = (len * threshold + 99) / 100;
|
||||
else
|
||||
low_water_mark = len;
|
||||
|
||||
if (!dm_tree_node_add_thin_pool_target(node, len,
|
||||
seg->transaction_id,
|
||||
metadata_dlid, pool_dlid,
|
||||
seg->chunk_size, seg->low_water_mark,
|
||||
seg->chunk_size, low_water_mark,
|
||||
seg->zero_new_blocks ? 0 : 1))
|
||||
return_0;
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ int id_valid(struct id *id)
|
||||
|
||||
for (i = 0; i < ID_LEN; i++)
|
||||
if (!_inverse_c[id->uuid[i]]) {
|
||||
log_error("UUID contains invalid character");
|
||||
log_error("UUID contains invalid character '%c'", id->uuid[i]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ struct segment_type *init_zero_segtype(struct cmd_context *cmd)
|
||||
return_NULL;
|
||||
|
||||
segtype->ops = &_zero_ops;
|
||||
segtype->name = "zero";
|
||||
segtype->name = SEG_TYPE_NAME_ZERO;
|
||||
segtype->flags = SEG_CAN_SPLIT | SEG_VIRTUAL | SEG_CANNOT_BE_ZEROED;
|
||||
|
||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||
|
||||
@@ -289,7 +289,7 @@ static int close_enough(double d1, double d2)
|
||||
return fabs(d1 - d2) < DBL_EPSILON;
|
||||
}
|
||||
|
||||
static int compare_value(struct dm_config_value *a, struct dm_config_value *b)
|
||||
int compare_value(struct dm_config_value *a, struct dm_config_value *b)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ struct dm_config_node *make_config_node(struct dm_config_tree *cft,
|
||||
struct dm_config_node *parent,
|
||||
struct dm_config_node *pre_sib);
|
||||
|
||||
int compare_value(struct dm_config_value *a, struct dm_config_value *b);
|
||||
int compare_config(struct dm_config_node *a, struct dm_config_node *b);
|
||||
|
||||
struct dm_config_node *make_text_node(struct dm_config_tree *cft,
|
||||
|
||||
@@ -160,12 +160,18 @@ static int _parse_one(log_state *s, int outlet, const char *type, int enable)
|
||||
if (!strcmp(type, "all"))
|
||||
for (i = 0; i < 32; ++i)
|
||||
daemon_log_enable(s, outlet, i, enable);
|
||||
else if (!strcmp(type, "fatal"))
|
||||
daemon_log_enable(s, outlet, DAEMON_LOG_FATAL, enable);
|
||||
else if (!strcmp(type, "error"))
|
||||
daemon_log_enable(s, outlet, DAEMON_LOG_ERROR, enable);
|
||||
else if (!strcmp(type, "warn"))
|
||||
daemon_log_enable(s, outlet, DAEMON_LOG_WARN, enable);
|
||||
else if (!strcmp(type, "info"))
|
||||
daemon_log_enable(s, outlet, DAEMON_LOG_INFO, enable);
|
||||
else if (!strcmp(type, "wire"))
|
||||
daemon_log_enable(s, outlet, DAEMON_LOG_WIRE, enable);
|
||||
else if (!strcmp(type, "debug"))
|
||||
daemon_log_enable(s, outlet, DAEMON_LOG_DEBUG, enable);
|
||||
else
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -262,7 +262,6 @@ dm_tree_node_set_thin_external_origin
|
||||
dm_tree_node_set_thin_pool_discard
|
||||
dm_tree_node_set_thin_pool_error_if_no_space
|
||||
dm_tree_node_set_udev_flags
|
||||
dm_tree_node_size_changed
|
||||
dm_tree_preload_children
|
||||
dm_tree_retry_remove
|
||||
dm_tree_set_cookie
|
||||
|
||||
3
libdm/.exported_symbols.DM_1_02_110
Normal file
3
libdm/.exported_symbols.DM_1_02_110
Normal file
@@ -0,0 +1,3 @@
|
||||
dm_report_compact_given_fields
|
||||
dm_hold_control_dev
|
||||
dm_tree_node_size_changed
|
||||
@@ -21,13 +21,14 @@ SOURCES =\
|
||||
datastruct/hash.c \
|
||||
datastruct/list.c \
|
||||
libdm-common.c \
|
||||
libdm-file.c \
|
||||
libdm-deptree.c \
|
||||
libdm-string.c \
|
||||
libdm-report.c \
|
||||
libdm-timestamp.c \
|
||||
libdm-stats.c \
|
||||
libdm-config.c \
|
||||
libdm-deptree.c \
|
||||
libdm-file.c \
|
||||
libdm-report.c \
|
||||
libdm-stats.c \
|
||||
libdm-string.c \
|
||||
libdm-targets.c \
|
||||
libdm-timestamp.c \
|
||||
mm/dbg_malloc.c \
|
||||
mm/pool.c \
|
||||
regex/matcher.c \
|
||||
|
||||
@@ -81,6 +81,7 @@ static dm_bitset_t _dm_bitset = NULL;
|
||||
static uint32_t _dm_device_major = 0;
|
||||
|
||||
static int _control_fd = -1;
|
||||
static int _hold_control_fd_open = 0;
|
||||
static int _version_checked = 0;
|
||||
static int _version_ok = 1;
|
||||
static unsigned _ioctl_buffer_double_factor = 0;
|
||||
@@ -1201,8 +1202,13 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
|
||||
|
||||
if (dmt->type == DM_DEVICE_SUSPEND)
|
||||
dmi->flags |= DM_SUSPEND_FLAG;
|
||||
if (dmt->no_flush)
|
||||
dmi->flags |= DM_NOFLUSH_FLAG;
|
||||
if (dmt->no_flush) {
|
||||
if (_dm_version_minor < 12)
|
||||
log_verbose("No flush flag unsupported by kernel. "
|
||||
"Buffers will be flushed.");
|
||||
else
|
||||
dmi->flags |= DM_NOFLUSH_FLAG;
|
||||
}
|
||||
if (dmt->read_only)
|
||||
dmi->flags |= DM_READONLY_FLAG;
|
||||
if (dmt->skip_lockfs)
|
||||
@@ -2079,9 +2085,18 @@ repeat_ioctl:
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dm_hold_control_dev(int hold_open)
|
||||
{
|
||||
_hold_control_fd_open = hold_open ? 1 : 0;
|
||||
|
||||
log_debug("Hold of control device is now %sset.",
|
||||
_hold_control_fd_open ? "" : "un");
|
||||
}
|
||||
|
||||
void dm_lib_release(void)
|
||||
{
|
||||
_close_control_fd();
|
||||
if (!_hold_control_fd_open)
|
||||
_close_control_fd();
|
||||
dm_timestamp_destroy(_dm_ioctl_timestamp);
|
||||
_dm_ioctl_timestamp = NULL;
|
||||
update_devs();
|
||||
|
||||
@@ -352,6 +352,7 @@ struct dm_status_snapshot {
|
||||
unsigned has_metadata_sectors : 1; /* set when metadata_sectors is present */
|
||||
unsigned invalid : 1; /* set when snapshot is invalidated */
|
||||
unsigned merge_failed : 1; /* set when snapshot merge failed */
|
||||
unsigned overflow : 1; /* set when snapshot overflows */
|
||||
};
|
||||
|
||||
int dm_get_status_snapshot(struct dm_pool *mem, const char *params,
|
||||
@@ -1167,6 +1168,9 @@ void dm_lib_init(void) __attribute__((constructor));
|
||||
void dm_lib_release(void);
|
||||
void dm_lib_exit(void) __attribute__((destructor));
|
||||
|
||||
/* An optimisation for clients making repeated calls involving dm ioctls */
|
||||
void dm_hold_control_dev(int hold_open);
|
||||
|
||||
/*
|
||||
* Use NULL for all devices.
|
||||
*/
|
||||
@@ -1252,6 +1256,11 @@ const char *dm_tree_node_get_name(const struct dm_tree_node *node);
|
||||
const char *dm_tree_node_get_uuid(const struct dm_tree_node *node);
|
||||
const struct dm_info *dm_tree_node_get_info(const struct dm_tree_node *node);
|
||||
void *dm_tree_node_get_context(const struct dm_tree_node *node);
|
||||
/*
|
||||
* Returns 0 when node size and its children is unchanged.
|
||||
* Returns 1 when node or any of its children has increased size.
|
||||
* Rerurns -1 when node or any of its children has reduced size.
|
||||
*/
|
||||
int dm_tree_node_size_changed(const struct dm_tree_node *dnode);
|
||||
|
||||
/*
|
||||
@@ -2547,6 +2556,13 @@ int dm_report_object_is_selected(struct dm_report *rh, void *object, int do_outp
|
||||
*/
|
||||
int dm_report_compact_fields(struct dm_report *rh);
|
||||
|
||||
/*
|
||||
* The same as dm_report_compact_fields, but for selected fields only.
|
||||
* The "fields" arg is comma separated list of field names (the same format
|
||||
* as used for "output_fields" arg in dm_report_init fn).
|
||||
*/
|
||||
int dm_report_compact_given_fields(struct dm_report *rh, const char *fields);
|
||||
|
||||
/*
|
||||
* Returns 1 if there is no data waiting to be output.
|
||||
*/
|
||||
|
||||
@@ -1038,7 +1038,7 @@ static int _rm_dev_node(const char *dev_name, int warn_if_udev_failed)
|
||||
|
||||
if (!_build_dev_path(path, sizeof(path), dev_name))
|
||||
return_0;
|
||||
if (stat(path, &info) < 0)
|
||||
if (lstat(path, &info) < 0)
|
||||
return 1;
|
||||
else if (_warn_if_op_needed(warn_if_udev_failed))
|
||||
log_warn("Node %s was not removed by udev. "
|
||||
@@ -1060,20 +1060,31 @@ static int _rename_dev_node(const char *old_name, const char *new_name,
|
||||
{
|
||||
char oldpath[PATH_MAX];
|
||||
char newpath[PATH_MAX];
|
||||
struct stat info;
|
||||
struct stat info, info2;
|
||||
struct stat *info_block_dev;
|
||||
|
||||
if (!_build_dev_path(oldpath, sizeof(oldpath), old_name) ||
|
||||
!_build_dev_path(newpath, sizeof(newpath), new_name))
|
||||
return_0;
|
||||
|
||||
if (stat(newpath, &info) == 0) {
|
||||
if (!S_ISBLK(info.st_mode)) {
|
||||
if (lstat(newpath, &info) == 0) {
|
||||
if (S_ISLNK(info.st_mode)) {
|
||||
if (stat(newpath, &info2) == 0)
|
||||
info_block_dev = &info2;
|
||||
else {
|
||||
log_sys_error("stat", newpath);
|
||||
return 0;
|
||||
}
|
||||
} else
|
||||
info_block_dev = &info;
|
||||
|
||||
if (!S_ISBLK(info_block_dev->st_mode)) {
|
||||
log_error("A non-block device file at '%s' "
|
||||
"is already present", newpath);
|
||||
return 0;
|
||||
}
|
||||
else if (_warn_if_op_needed(warn_if_udev_failed)) {
|
||||
if (stat(oldpath, &info) < 0 &&
|
||||
if (lstat(oldpath, &info) < 0 &&
|
||||
errno == ENOENT)
|
||||
/* assume udev already deleted this */
|
||||
return 1;
|
||||
|
||||
@@ -51,4 +51,6 @@ void selinux_release(void);
|
||||
void inc_suspended(void);
|
||||
void dec_suspended(void);
|
||||
|
||||
int parse_thin_pool_status(const char *params, struct dm_status_thin_pool *s);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -157,21 +157,18 @@ struct dm_config_tree *dm_config_insert_cascaded_tree(struct dm_config_tree *fir
|
||||
|
||||
static struct dm_config_node *_config_reverse(struct dm_config_node *head)
|
||||
{
|
||||
if (!head)
|
||||
return NULL;
|
||||
|
||||
struct dm_config_node *left = head, *middle = NULL, *right = NULL;
|
||||
|
||||
do {
|
||||
while (left) {
|
||||
right = middle;
|
||||
middle = left;
|
||||
left = left->sib;
|
||||
middle->sib = right;
|
||||
middle->child = _config_reverse(middle->child);
|
||||
} while (left);
|
||||
}
|
||||
|
||||
return middle;
|
||||
};
|
||||
}
|
||||
|
||||
int dm_config_parse(struct dm_config_tree *cft, const char *start, const char *end)
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user