1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-10-14 15:33:15 +03:00

Compare commits

...

326 Commits

Author SHA1 Message Date
Bryn M. Reeves
d4acf8b533 dmstats: separate report and sample clocks
Maintain separate timestamps for sampling interval and report
waits and correct the sleep interval for the time spent collecting
and processing stats.
2015-08-08 23:59:06 +01:00
Bryn M. Reeves
dfb4560e24 dmstats: add libdm-stats library and 'dmsetup stats' command
Add the libdm-stats module to libdm. This implements a simple interface
for creating, managing and interrogating I/O statistics regions and
areas on device-mapper devices.

The library interface is documented in libdevmapper.h and provides a
'dm_stats' handle that is used to perform statistics operations and
obtain data. Methods are provided to return baisc count values and to
derive time-based metrics when a suitable interval estimate is provided.

The dm_stats handle contains a pointer to a table of one or more
dm_stats_region objects representing the regions registered with the
@stats_create message. These in turn point to a table of one or more
dm_stats_counters objects containing the counter sets for each defined
area within the region:

  dm_stats->dm_stats_region[nr_regions]->dm_stats_counters[nr_areas]

This structure is private to the library and may change in future
versions: all users should make use of the public interface and treat
the dm_stats type as an opaque handle.

Regions and counter sets are stored in order of increasing region_id.

Public methods are provided to create and destroy handles and to
list, create, and destroy, statistics regions as well as to obtain and
parse the actual counter data.

Linux iostat-style derived performance metrics are provided to return
higher-level performance metrics.

This commit also adds arguments, report types, and a 'stats' command to
dmsetup and implements 'clear', 'create', 'delete', 'list', 'print', and
'report' sub-commands.

The dmsetup _display_info_cols() function is adapted to allow reporting
of statistics with the DR_STATS report type: since a single object
(device) may have many rows of statistics to report the call to
dm_report_object() is placed inside a loop over each statistics area
present (for non-stats reports or for devices with a single region
spanning the entire device the body of the loop will be executed exactly
once).
2015-08-08 23:39:22 +01:00
Bryn M. Reeves
f06d866110 WHATS_NEW_DM: Update for preliminary stats commits
Add entries for dm_report_column_headings() and report row leaks
and remove the dm_report interval/wait entry.
2015-08-08 17:48:30 +01:00
Bryn M. Reeves
3638c05ec9 libdm: do not attempt to output column headings with --rows
Columns-as-rows output does not use _report_headings(); don't
try to call it when rh->flags & DM_REPORT_OUTPUT_COLUMNS_AS_ROWS.
2015-08-08 17:48:30 +01:00
Bryn M. Reeves
54815fff06 libdm: remove report interval support
Don't do interval management and external timekeeping for stats in
dm_report: let applications handle this on their own.

Since this has not been included in a release remove it from the
library entirely and handle report timing directly inside dmsetup.
2015-08-08 11:48:12 +01:00
Bryn M. Reeves
666c77c0f2 libdm: add dm_report_column_headings
Add a function to print column headings regardless of whether they
have already been output. This will be used by dmstats to issue
periodic reminders of the column headings.

This patch removes a check for RH_HEADINGS_PRINTED from
_report_headings that prevents headings being displayed if the flag
is already set; this check is redundant since the only existing
caller (_output_as_columns()) already tests the flag before
calling the function.
2015-08-08 11:43:52 +01:00
Bryn M. Reeves
cafe145ba2 libdm: fix report rows and headings memory and state leaks
Not releasing objects back to the pool is fine for short-lived
pools since the memory will be freed when dm_pool_destroy() is
called.

Any pool that may be long-lived needs to be more careful to free
objects back to the pool to avoid leaking memory that will not be
reclaimed until the pool is destroyed at process exit time.

The report pool currently leaks each headings line and some row
data.

Although dm_report_output() tries to free the first allocated row
this may end up freeing a later row due to sorting of the row list
while reporting. Store a pointer to the first allocated row from
_do_report_obect() instead and free this at the end of
_output_as_columns(), _output_as_rows(), and dm_report_clear().

Also make sure to call dm_pool_free() for the headings line built
in _report_headings().

When dmstats is introduced it will maintain dm_report objects for
the whole lifetime of the process: without these changes a stats
report could leak around 600k in 10m (exact rate depends on field
selection and data values):

 top - 12:11:32 up 4 days,  3:16, 15 users,  load average: 0.01, 0.12, 0.14
  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
 6473 root      20   0  130196   3124   2792 S   0.0  0.0   0:00.00 dmstats

 top - 12:22:04 up 4 days,  3:26, 15 users,  load average: 0.06, 0.11, 0.13
  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
 6498 root      20   0  130836   3712   2752 S   0.0  0.0   0:00.60 dmstats

With this patch no increase in RSS is seen:

 top - 13:54:58 up 4 days,  4:59, 15 users,  load average: 0.12, 0.14, 0.14
  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
13962 root      20   0  130196   2996   2688 S   0.0  0.0   0:00.00 dmstats

 top - 14:04:31 up 4 days,  5:09, 15 users,  load average: 1.02, 0.67, 0.36
  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
13962 root      20   0  130196   2996   2688 S   0.3  0.0   0:00.32 dmstats

This also affects report output for repeating reports in the
DM_REPORT_OUTPUT_COLUMNS_AS_ROWS case; row state is not fully cleared for
the next iteration leading to progressive growth of the heading width:

vg_hex-lv_home:vg_hex-lv_swap:vg_hex-lv_root:luks-79733921-3f68-4c92-9eb7-d0aca4c6ba3e:vg_hex-lv_images
253:253:253:253:253
2:0:1:4:3
L--w:L--w:L--w:L--w:L--w
1:2:1:1:1
3:1:1:1:2
0:0:0:0:0
LVM-9t8ITqLZa6AuuyVoz5Olp1KwF9ZDBfOiv08BCGvF4WsJSqWUDUt7qtf2hEmjtVvo:LVM-9t8ITqLZa6AuuyVoz5Olp1KwF9ZDBfOiKf7XIiwdAYOJfaGhQe9fu26cTEICGgFS:LVM-9t8ITqLZa6AuuyVoz5Olp1KwF9ZDBfOiEZj7ZXbmrWDuGhd7vvi88VF0NdTMG8iA:CRYPT-LUKS1-797339213f684c929eb7d0aca4c6ba3e-luks-79733921-3f68-4c92-9eb7-d0aca4c6ba3e:LVM-9t8ITqLZa6AuuyVoz5Olp1KwF9ZDBfOi2rKredlBPnw2X7v1BiCuEpFo6gaE7BRw

:::::vg_hex-lv_home:vg_hex-lv_swap:vg_hex-lv_root:luks-79733921-3f68-4c92-9eb7-d0aca4c6ba3e:vg_hex-lv_images
:::::253:253:253:253:253
:::::2:0:1:4:3
:::::L--w:L--w:L--w:L--w:L--w
:::::1:2:1:1:1
:::::3:1:1:1:2
:::::0:0:0:0:0
:::::LVM-9t8ITqLZa6AuuyVoz5Olp1KwF9ZDBfOiv08BCGvF4WsJSqWUDUt7qtf2hEmjtVvo:LVM-9t8ITqLZa6AuuyVoz5Olp1KwF9ZDBfOiKf7XIiwdAYOJfaGhQe9fu26cTEICGgFS:LVM-9t8ITqLZa6AuuyVoz5Olp1KwF9ZDBfOiEZj7ZXbmrWDuGhd7vvi88VF0NdTMG8iA:CRYPT-LUKS1-797339213f684c929eb7d0aca4c6ba3e-luks-79733921-3f68-4c92-9eb7-d0aca4c6ba3e:LVM-9t8ITqLZa6AuuyVoz5Olp1KwF9ZDBfOi2rKredlBPnw2X7v1BiCuEpFo6gaE7BRw
2015-08-08 11:35:10 +01:00
Bryn M. Reeves
974e7b9220 libdm: ensure new dm_timestamp objects are initialized
Allocate a dm_timestamp with dm_zalloc() to ensure the memory is
initialized to a known state.
2015-08-08 10:42:14 +01:00
David Teigland
b59cdf0892 man: mention system ID in vgexport and vgimport 2015-08-07 16:35:07 -05:00
David Teigland
993fe07a3c man: add lockd bits to relevant commands 2015-08-07 16:25:00 -05:00
David Teigland
2bbf2fa8eb man lvmlockd: update 2015-08-07 15:18:44 -05:00
David Teigland
1c013e7ae2 man lvmcache: mention LVs must be in the same VG 2015-08-06 10:06:21 -05:00
David Teigland
fd1782b5fc lvmlockd: handle loss of sanlock lease storage
This adds the infrastructure, code paths, error reporting,
etc. to handle storage errors, or storage loss, under the
sanlock leases in a VG that is being used.  The loss of
storage means sanlock cannot renew its leases, which means
that the host needs to stop using the shared VG before its
leases expire.

This still requires manually shutting down a VG that has
lost lease storage, e.g. unmounting file systems,
deactivating LVs in the VG.  The next step is to
automatically use a command like blkdeactivate to do that.
2015-08-05 10:21:45 -05:00
Alasdair G Kergon
559ca8bc65 dmsetup: Report timestamps of ioctls with -vvv.
If enabled, record timestamp immediately after the ioctl() returns.
2015-08-05 08:28:35 +01:00
Alasdair G Kergon
2f334afb98 libdm: Whitespace. 2015-08-05 05:21:58 +01:00
Alasdair G Kergon
88551add97 libdm: Whitespace. 2015-08-05 05:11:42 +01:00
Alasdair G Kergon
23e8e849e4 libdm: Sort new exported symbols. 2015-08-05 05:07:45 +01:00
Alasdair G Kergon
362a1a5a82 dmsetup: Tidy whitespace. 2015-08-05 05:03:33 +01:00
Peter Rajnoha
ce1528359a man: document --nameprefixes 2015-08-04 14:03:50 +02:00
Peter Rajnoha
f02cdcff00 coverity: check vg->lvm1_system_id is not NULL before calling strncmp with that
lib/format1/import-export.c:167: var_deref_model: Passing null pointer "vg->lvm1_system_id" to "strncmp", which dereferences it.
2015-08-04 10:35:31 +02:00
Peter Rajnoha
1f3d04cddf coverity: variable init must be done before its use
tools/polldaemon.c:465: uninit_use_in_call: Using uninitialized value "id.vg_name" when calling "print_log".
tools/polldaemon.c:465: uninit_use_in_call: Using uninitialized value "id.lv_name" when calling "print_log".
2015-08-04 09:51:16 +02:00
Peter Rajnoha
c78033233a coverity: return value check in lvmlockd-dlm
daemons/lvmlockd/lvmlockd-dlm.c:647: check_return: Calling "closedir" without checking return value (as is done elsewhere 13 out of 14 times).
2015-08-04 09:49:29 +02:00
Peter Rajnoha
83541123c8 coverity: fix cppcheck warnings
/lib/log/log.c:88: warning[invalidScanfArgType_int]: %llu in format string (no. 2) requires 'unsigned long long *' but the argument type is 'long long *'.
daemons/lvmlockd/lvmlockd-core.c:791: error[uninitstring]: Dangerous usage of 'version' (strncpy doesn't always null-terminate it).
2015-08-04 09:33:55 +02:00
Peter Rajnoha
46e6b2b86e coverity: fix possible resource leak in lvmpolld-core
/daemons/lvmpolld/lvmpolld-core.c:573: leaked_storage: Variable "cmdargv" going out of scope leaks the storage it points to.
2015-08-04 09:25:47 +02:00
Peter Rajnoha
6ac5689ce4 report: also recognize variants without underscores for <prefix>_all fields
For example: "pvs -o pv_all" and pvs -o pvall" are same.
2015-08-04 09:03:31 +02:00
David Teigland
d11f8d4228 lvmlockd: automatically remove the dlm global lockspace
The dlm global lockspace is automatically added when the
first dlm VG lockspace is added.  Reverse this by removing
the dlm global lockspace after the last dlm VG lockspace
is removed.  (Remove old non-working code that did this
based on an old command that could explicitly add/remove
the dlm global lockspace.)
2015-08-03 10:23:01 -05:00
Peter Rajnoha
71dbe47619 report: update comment for _is_same_field fn 2015-08-03 16:47:02 +02:00
Peter Rajnoha
a5b476a7d3 report: recognize report field name variants without any underscores too
Whenver reporting field name is registered with libdevmapper and if
the field name contains any number of underscores ('_'), libdm
can now automatically recognize any of its variant without any
underscores used.

For example:

..for underscores in prefixes:
  pvs -o pv_name
  pvs -o name
  pvs -o pvname (newly recognized besides pvname)

..for underscores in the name:
  lvs -o cache_mode
  lvs -o cachemode

..or even multiple underscores:
  pvs -o pv___na___me

It's all variant of the same field name.
2015-08-03 16:29:50 +02:00
Peter Rajnoha
b3997469b5 toolcontext: do not set cmd->initialized_connections = 0 on destroy_toolcontext
The whole cmd context is freed completely in destroy_toolcontext, so do
not write to any of dead cmd variables.
2015-08-03 16:17:17 +02:00
Bryn M. Reeves
519c309952 dmsetup: Use argcp and argvp. 2015-07-31 22:53:38 +01:00
Bryn M. Reeves
a161e29c59 dmsetup: Add --count and --interval to reports.
For example, to monitor active devices every second you can now run
dmsetup info -c --count 0.
2015-07-31 21:59:34 +01:00
David Teigland
72f754e2bc lockd: remove ignorelockingfailure checks
These code paths were effectively unused.  The checks
had been added long ago without any real thought behind
what they should do or be used for.
2015-07-31 15:51:50 -05:00
David Teigland
439a579aa2 vgchange/lvchange: allow deactivation without locking
If locking with lvmlockd has failed, allow LVs to be deactivated.
2015-07-31 14:11:24 -05:00
Alasdair G Kergon
649c9d4719 dmsetup: Allow commands to have subcommands.
No commands set has_subcommands yet.

Move multiple device loop to separate function because we'll
soon want to call it repeatedly.

(Based on patch from bmr.)
2015-07-31 19:09:31 +01:00
Alasdair G Kergon
51f89f2fbd dmsetup: Add subcommand parameter.
Not yet used.
Allows for dmsetup stats <subcommand> dev1 dev2...
2015-07-31 17:47:03 +01:00
Alasdair G Kergon
e06d188f0d dmsetup: _find_command returns const 2015-07-31 16:58:14 +01:00
Alasdair G Kergon
fef3cb3f21 dmsetup: Add _dmsetup to help and usage fns.
Prepare for dmstats.
Adjust some text to avoid 80-char wrap.
2015-07-31 16:26:38 +01:00
Alasdair G Kergon
027fe112ec dmsetup: Rename _commands to _dmsetup_commands.
We'll need to accommodate sub-commands for dmstats.
2015-07-31 16:13:45 +01:00
Peter Rajnoha
f54198eed6 toolcontext: use refresh_filters in refresh_toolcontext
Use refresh_filters instead of destroy_filters and init_filters
in refresh_toolcontext fn which deals with cmd->initialized.filters
correctly on refresh.
2015-07-31 10:25:36 +02:00
Marian Csontos
0dae377fbf test: Update Makefiles
- Add missing check_lvmpolld to toplevel Makefile
- Document check_system
2015-07-30 20:39:38 +02:00
Marian Csontos
8bc90a25c2 spec: lockd_dlm requires dlm-lib instead of dlm 2015-07-30 20:39:38 +02:00
David Teigland
b40ccdd57c lvmlockd: create sanlock lv large enough for existing lvs
When changing an existing VG to lock_type sanlock,
make the sanlock lv large enough to hold all the
locks needed for existing LVs.
2015-07-30 12:04:31 -05:00
David Teigland
78135c24b4 lvmlockd: small fixes and cleanup for lvmlockctl
. clean up the info output for readability
. remove some internal debug output
. fix the daemon quit option
2015-07-30 10:50:22 -05:00
Peter Rajnoha
d9c67a9b21 cleanup: toolcontext: move report_list_item_separator into its group 2015-07-30 16:14:10 +02:00
Peter Rajnoha
e6834b3237 cleanup: toolcontext: make cmd_context more readable
Just shuffle the items and put them into logical groups so it's
visible at first sight what each group contains - it makes it a bit
easier to make heads and tails of the whole cmd_context monster.
2015-07-30 16:01:02 +02:00
Peter Rajnoha
c0629c13fe commands: add new NO_METADATA_PROCESSING flag to selected commands
When a command is flagged with NO_METADATA_PROCESSING flag, it means
such command does not process any metadata and hence it doens't require
lvmetad, lvmpolld and it can get away with no locking too. These are
mostly simple commands (like lvmconfig/dumpconfig, version, types,
segtypes and other builtin commands that do not process metadata
in any way).

At first, when lvm command is executed, create toolcontext without
initializing connections (lvmetad,lvmpolld) and without initializing
filters (which depend on connections init). Instead, delay this
initialization until we know we need this. That is, until the
lvm_run_command fn is called in which we know what the actual
command to run is and hence we can avoid any connection, filter
or locking initiliazation for commands that would not make use
of it anyway.

For all the other create_toolcontext calls, we keep the original
behaviour - the filters and connections are initialized together
with the toolcontext.
2015-07-30 13:56:13 +02:00
Peter Rajnoha
f6473baffc toolcontext: add switches to create_toolcontext for connections and filters init
Make it possible to decide whether we want to initialize connections and
filters together with toolcontext creation.

Add "filters" and "connections" fields to struct
cmd_context_initialized_parts and set these in cmd_context.initialized
instance accordingly.

(For now, all create_toolcontext calls do initialize connections and
filters, we'll change that in subsequent patch appropriately.)
2015-07-30 13:54:09 +02:00
Peter Rajnoha
3e343ba5ef refactor: toolcontext: move lvmetad and lvmpolld init into separate function
Move original lvmetad and lvmpolld initialization code from
_process_config fn to their own functions _init_lvmetad and
_init_lvmpolld (both covered with single _init_connections fn).
2015-07-30 13:54:09 +02:00
Peter Rajnoha
6b0c464a34 refactor: toolcontext: add struct cmd_context_initialized_parts
Add struct cmd_context_initialized_parts to wrap up information
about which cmd context pieces are initialized and add variable
of this struct type into struct cmd_context.

Also, move existing "config_initialized" variable that was directly
part of cmd_context into the new cmd_context.initialized wrapper.

We'll be adding more items into the struct cmd_context_initialized_parts
with subsequent patches...
2015-07-30 13:54:05 +02:00
David Teigland
9aabf441bd vgremove: warn when removing sanlock global lock
When the sanlock VG holding the global lock is removed,
print a warning indicating that the global needs to be
enabled in another sanlock VG.
2015-07-29 14:27:32 -05:00
David Teigland
772b54a08b vgcreate: improve checks for existing global lock
This tries harder to avoid creating duplicate global locks in
sanlock VGs by refusing to create a new sanlock VG with a
global lock if other sanlock VGs exist that may have a gl.
2015-07-29 14:27:32 -05:00
David Teigland
e593213b87 lvmcache: add lock_type to VG summary and info structs
vgsummary information contains provisional VG information
that is obtained without holding the VG lock.  This info
can be used to lock the VG, and then read it with vg_read().
After the VG is read properly, the vgsummary info should
be verified.

Add the VG lock_type to the vgsummary.  It needs to be
known before the VG can be locked and read.
2015-07-29 14:27:32 -05:00
Alasdair G Kergon
3cd644aeb5 libdm: Require librt for new dm_timestamp. 2015-07-29 19:30:22 +01:00
Alasdair G Kergon
a28fb37b9e libdm: Add dm_timestamp functions. 2015-07-29 19:21:07 +01:00
Alasdair G Kergon
a5491d3698 dmsetup: Accept vg/lv name format.
If there is exactly one / which is not the first character, check
for /dev/vg/lv (as dm_dir()/../$name i.e. /dev/mapper/../vg/lv.)
2015-07-29 12:24:36 +01:00
Peter Rajnoha
ca0d9a70d1 dmsetup: remove dead code that covered "info -c -o help" case once
The "-o help" is now handled as implicit field and it gets processed
just like any other field - all handled by libdevmapper now.
2015-07-29 13:16:09 +02:00
Peter Rajnoha
cf700151eb cache: fix regression causing some PVs to bypass filters
This is a regression introduced by commit
6c0e44d5a2 which changed
the way dev_cache_get fn works - before this patch, when a
device was not found, it fired a full rescan to correct the
cache. However, the change coming with that commit missed
this full_rescan call, causing the lvmcache to still contain
info about PVs which should be filtered now.

Such situation may have happened by coincidence of using
old persistent cache (/etc/lvm/cache/.cache) which does not
reflect the actual state anymore, a device name/symlink which
now points to a device which should be filtered and a fact we
keep info about usable DM devices in .cache no matter what
the filter setting is.

This bug could be hidden though by changes introduced in
commit f1a000a477 as it
calls full_rescan earlier before this problem is hit.
But we need to fix this anyway for the dev_cache_get
to be correct if we happen to use the same code path
again somewhere sometime.

For example, simple reproducer was (before commit
1a000a477558e157532d5f2cd2f9c9139d4f87c):

- /dev/sda contains a PV header with UUID y5PzRD-RBAv-7sBx-V3SP-vDmy-DeSq-GUh65M

- lvm.conf: filter = [ "r|.*|" ]

- rm -f .cache (to start with clean state)

- dmsetup create test --table "0 8388608 linear /dev/sda 0" (8388608 is
  just the size of the /dev/sda device I use in the reproducer)

- pvs (this will create .cache file which contains
  "/dev/disk/by-id/lvm-pv-uuid-y5PzRD-RBAv-7sBx-V3SP-vDmy-DeSq-GUh65M"
  as well as "/dev/mapper/test" and the target node "/dev/dm-1" - all the
  usable DM mappings (and their symlinks) get into the .cache file even
  though the filter "is set to "ignore all" - we do this - so far it's OK)

- dmsetup remove test (so we end up with /dev/disk/by-id/lvm-pv-uuid-...
  pointing to the /dev/sda now since it's the underlying device
  containing the actual PV header)

- now calling "pvs" with such .cache file and we get:
$ pvs
  PV                                                                 VG  Fmt  Attr PSize PFree
  /dev/disk/by-id/lvm-pv-uuid-y5PzRD-RBAv-7sBx-V3SP-vDmy-DeSq-GUh65M vg  lvm2 a--  4.00g    0

Even though we have set filter = [ "r|.*|" ] in the lvm.conf file!
2015-07-29 10:19:12 +02:00
Alasdair G Kergon
af1c7bf0c7 libdm: Add dm_size_to_string to libdevmapper.
Moved out from lib/display and a little documentation added.
It's tuned to LVM's requirements historically and its behaviour
might not always be what you would expect.
2015-07-27 21:30:20 +01:00
Alasdair G Kergon
fa11ddd7df lvmlockd: Drop -lrt now handled by configure. 2015-07-27 14:53:08 +01:00
Alasdair G Kergon
3e333e9b5c configure: Enable realtime by default, if present. 2015-07-27 14:44:58 +01:00
Alasdair G Kergon
1568ed4d20 configure: Add missing checks. 2015-07-27 14:26:56 +01:00
Alasdair G Kergon
3934ade5a2 gitignore: Update for in-place build. 2015-07-27 13:18:35 +01:00
Alasdair G Kergon
f4fa3e1a6b post-release 2015-07-24 23:39:54 +01:00
Alasdair G Kergon
ce6a0f4469 post-release 2015-07-24 23:21:51 +01:00
Alasdair G Kergon
33eb7d7dfb pre-release 2015-07-24 23:20:42 +01:00
Alasdair G Kergon
705caa8c32 tools: Streamline long option hyphen removal. 2015-07-24 19:45:49 +01:00
David Teigland
c1f5ac3eca lockd: remove an unreachable global lock condition
There is no longer an "enable" option for the global lock,
so remove the bit of code that was checking for it.  It
was an optional variation anyway, and not one that was likely
to be used.

Also update the corresponding comment describing global lock
creation.
2015-07-24 10:56:08 -05:00
David Teigland
bcb875dcb1 Fix dehyphenation cases
Stop removing hyphens when = is seen.  With an option
like --profile=thin-performance, the hyphen removal
will stop at = and will not remove - after thin.

Stop removing hyphens altogether when a stand alone arg
of -- appears.
2015-07-24 10:25:13 -05:00
Alasdair G Kergon
be66243933 clvmd: Fix freeze if client dies holding locks.
Simply running concurrent copies of 'pvscan | true' is enough to make
clvmd freeze: pvscan exits on the EPIPE without first releasing the
global lock.

clvmd notices the client disappear but because the cleanup code that
releases the locks is triggered from within some processing after the
next select() returns, and that processing can 'break' after doing just
one action, it sometimes never releases the locks to other clients.

Move the cleanup code before the select.
Check all fds after select().
Improve some debug messages and warn in the unlikely event that
select() capacity could soon be exceeded.
2015-07-23 23:10:16 +01:00
David Teigland
57534733b7 lvmlockd: improve check for duplicate global locks
When there are duplicate global locks, check if the gl
is still enabled each time a gl or vg lock is acquired
in the lockspace.  Once one of the duplicates is disabled,
then other hosts will recognize that the issue is resolved
without needing to restart the lockspaces.
2015-07-23 10:39:11 -05:00
Alasdair G Kergon
1612c570b6 libdm: Use wrappers for all malloc functions.
Move the DEBUG_MEM decision inside libdevmapper.so instead of exposing
it in libdevmapper.h which causes failures if the binary and library
were compiled with opposite debugging settings.
2015-07-22 23:11:48 +01:00
David Teigland
b92e502695 pvscan: skip autoactivation for lockd VGs
pvscan autoactivation does not work for lockd VGs because
lock start is needed on a lockd VG before locking can be
done for it.  Add a check to skip the attempt at autoactivate
rather than calling it, knowing it will fail.

Add a comment explaining why pvscan --cache works fine for
lockd VGs without locks, and why autoactivate is not done.
2015-07-22 15:44:20 -05:00
David Teigland
27e6aee390 lvconvert: merge polling fixes for lockd
. the poll check will eventually call finish which will
  write the VG, so an ex VG lock is needed from lvmlockd.

. fix missing unlock on poll error path

. remove the lockd locking while monitoring the progress
  of the command, as suggested by the earlier FIXME comment,
  as it's not needed.
2015-07-22 12:28:06 -05:00
Peter Rajnoha
8bfcefe11a config: add CFG_SECTION_NO_CHECK flag
The CFG_SECTION_NO_CHECK flag can be used to mark a section
and its whole subtree as containing settings where checks
won't be made (lvmconfig --validate).

These are setting where we don't know the names and and type
in advance and they're recognized in runtime. As we don't know
the type and name in advance, we can't do any checks here
of course.

Use this flag with great care as it disables config checks
for the whole config subtree found under such section.

This flag is going to be used by subsequent patches from
Zdenek to support some cache settings...
2015-07-22 14:25:42 +02:00
Ondrej Kozina
00d24511bc lvconvert: remove unused struct members 2015-07-22 12:56:43 +02:00
Ondrej Kozina
03762f42c1 lvconvert: retain retcode consistency
Always return the highest retcode caught during convert command
(regression in commit ae88bf03a1).
Also minor code cleanup.
2015-07-22 12:26:46 +02:00
David Teigland
ae88bf03a1 lvconvert: fix polling outside of core lvconvert
Recent change to move the polling outside of core lvconvert
code was wrongly using 'lv' and 'vg' structs which can't be
used outside of the core code, which caused seg fault.

Properly isolate all use of lv structs within the core of
the lvconvert code, saving any information necessary,
(esp lvid).  After the core of lvconvert is done, use
the saved information to do polling.

FIXME: the need for is_merging_origin and is_merging_origin_thin
in this patch is ugly, and a cleaner way should be found to deal
with that than what is done here.

Also it effectively removed all hacks in _lvconvert_merge_single
performing ugly: VG reread, unlock, polling, lock sequence.

Moreover all polling operations are postponed after all conversions
are finished.

lvm2 (while locking via lvmlockd) should now be able to run with
or without lvmpolld while performing poll operations originating
in lvconvert command.

Signed-off-by: Ondrej Kozina <okozina@redhat.com>
2015-07-22 10:38:02 +02:00
Peter Rajnoha
c3fddb0fbb wiping: add "Wiping skipped." for the message context to be complete 2015-07-21 11:00:43 +02:00
Peter Rajnoha
697fb353dc wiping: log_warn instead of log_error if blkid wipe ignored for a signature
Comply with the rules we have for log_error and log_warn...

$ pvcreate /dev/sda1
  Failed to get offset of the xfs_external_log signature on /dev/sda1.
  1 existing signature left on the device.
  Aborting pvcreate on /dev/sda1.

$ pvcreate /dev/sda1 --force
  WARNING: Failed to get offset of the xfs_external_log signature on /dev/sda1.
  Physical volume "/dev/sda1" successfully created
2015-07-21 10:34:04 +02:00
Peter Rajnoha
2a7c2539c6 wiping: ignore errors during detection if use_blkid_wiping=1 and --force is used
libblkid may return the list of signatures found, but it may not
provide offset and size for each signature detected. This may
happen in case signatures are mixed up or there are more, possibly
overlapping, signatures found.

Make lvm commands pass if such situation happens and we're using
--force (or any stronger force method).

For example:

$ pvcreate /dev/sda1
  Failed to get offset of the xfs_external_log signature on /dev/sda1.
  1 existing signature left on the device.
  Aborting pvcreate on /dev/sda1.

$ pvcreate --force /dev/sda1
  Failed to get offset of the xfs_external_log signature on /dev/sda1.
  Physical volume "/dev/sda1" successfully created
2015-07-21 09:54:20 +02:00
Alasdair G Kergon
500fd8b9bf log: Add DM_ABORT_ON_INTERNAL_ERRORS lvm override.
Recognise DM_ABORT_ON_INTERNAL_ERRORS in the lvm logging function as
well as the default dm function it replaces.
2015-07-20 15:48:59 +01:00
David Teigland
b4be988732 vgchange/lvchange: enforce the shared VG lock from lvmlockd
The vgchange/lvchange activation commands read the VG, and
don't write it, so they acquire a shared VG lock from lvmlockd.
When other commands fail to acquire a shared VG lock from
lvmlockd, a warning is printed and they continue without it.
(Without it, the VG metadata they display from lvmetad may
not be up to date.)

vgchange/lvchange -a shouldn't continue without the shared
lock for a couple reasons:

. Usually they will just continue on and fail to acquire the
  LV locks for activation, so continuing is pointless.

. More importantly, without the sh VG lock, the VG metadata
  used by the command may be stale, and the LV locks shown
  in the VG metadata may no longer be current.  In the
  case of sanlock, this would result in odd, unpredictable
  errors when lvmlockd doesn't find the expected lock on
  disk.  In the case of dlm, the invalid LV lock could be
  granted for the non-existing LV.

The solution is to not continue after the shared lock fails,
in the same way that a command fails if an exclusive lock fails.
2015-07-17 15:35:34 -05:00
Marian Csontos
b785a50da4 test: Help, default and relative paths in runner
Add help message.
Handle relative paths first.
Use `.` for OUTDIR instead of `/` if empty.
2015-07-17 20:36:50 +02:00
Marian Csontos
2bc0525e93 test: Fix hardcoded /usr/share in testsuite 2015-07-17 20:36:50 +02:00
David Teigland
85b42d7c95 lvmlockd: improve errors when lvm is built without a lock manager
When lvmlockd is compiled without support for one of the
lock managers (sanlock or dlm), and a command tries to use
one of them, explain that in the error message.
2015-07-17 11:16:18 -05:00
Alasdair G Kergon
c7fc06a262 test: Ignore known concurrent VG clvmd failure.
Don't abort test when clvmd processes two VGs concurrently.
  CLVMD: ioctl/libdm-iface.c:1940   Internal error: Performing unsafe table load while 3 device(s) are known to be suspended:  (253:19)
2015-07-17 12:56:52 +01:00
David Teigland
268f53ed0d lockd: fix error cases when built without lvmlockd
When lvm is built without lvmlockd support, vgcreate using a
shared lock type would succeed and create a local VG (the
--shared option was effectively ignored).  Make it fail.

Fix the same issue when using vgchange to change a VG to a
shared lock type.

Make the error messages consistent.
2015-07-16 15:22:06 -05:00
Alasdair G Kergon
b93b85378d alloc: Fix lvextend failure when varying stripes.
A segfault was reported when extending an LV with a smaller number of
stripes than originally used.  Under unusual circumstances, the cling
detection code could successfully find a match against the excess
stripe positions and think it had finished prematurely leading to an
allocation being pursued with a length of zero.

Rename ix_offset to num_positional_areas and move it to struct
alloc_state so that _is_condition() can obtain access to it.

In _is_condition(), areas_size can no longer be assumed to match the
number of positional slots being filled so check this newly-exposed
num_positional_areas directly instead.  If the slot is outside the
range we are trying to fill, just ignore the match for now.

(Also note that the code still only performs cling detection against
the first segment of the LV.)
2015-07-15 23:12:54 +01:00
David Teigland
e15db15926 vgimport: fix the all VGs case
The ALL_VGS_IS_DEFAULT flag was wrongly removed;
it is needed for vgimport -a to work.
2015-07-15 09:26:10 -05:00
David Teigland
2972604f0c vgexport: fix the all VGs case
The ALL_VGS_IS_DEFAULT flag was wrongly removed;
it is needed for vgexport -a to work.
2015-07-15 09:23:30 -05:00
Peter Rajnoha
d947a815e8 config: make a difference between "not found" and "is empty" in log msg for devices/preferred_names
Replace misleading "not found" in the log message when
devices/preferred_names is set to empty array:

Really not found:
device/dev-cache.c:689   devices/preferred_names not found in config: using built-in preferences

Found, but empty:
config/config.c:1431   Setting devices/preferred_names to preferred_names = [ ]
device/dev-cache.c:689   devices/preferred_names is empty: using built-in preferences
2015-07-15 16:14:51 +02:00
Peter Rajnoha
d10fb73f63 config: also log the value used if defined in config, not just defaults
Commit 7e728fe1a1 added a log call
directly in find_config_tree_array when defaults are used.

This patch also adds the log for the value which is found in
existing configuration and for which defaults are not used.

For example:

Defaults used:
config/config.c:1428   devices/scan not found in config: defaulting to scan = [ "/dev" ]

Value defined in configuration used:
config/config.c:1431   Setting devices/scan to scan = [ "/dev", "/mydev", "/abc" ]

This makes the logging consistent with the other find_config_tree_* functions.
2015-07-15 16:02:20 +02:00
Zdenek Kabelac
64c4106219 cleanup: drop unused header file 2015-07-15 13:10:22 +02:00
Zdenek Kabelac
c45e6e3c78 cleanup: avoid double assign
Variable n1 is assigned without using n1 before.
2015-07-15 13:10:22 +02:00
Zdenek Kabelac
a7101e7bfb cleanup: drop duplicated seg test
Test is already in seg_is_pool() if branch.
and one minor indent fix.
2015-07-15 13:10:22 +02:00
Zdenek Kabelac
beb65056cf makefiles: adding target for generating ctags
make tags generates traditional tags ctags ref list.
2015-07-15 13:10:22 +02:00
Zdenek Kabelac
c2d4330f27 cache: enhance cache-pool validation
Capture cache-pool without cache policy name set.
2015-07-15 13:10:22 +02:00
Zdenek Kabelac
077645476c cache: capture missing policy name
Policy name has to be always defined.
Capture it as an internal error before write.
When reading metadata without defined policy name, use default defined policy.

TODO: Unsure, but it might have to be actually always 'mq' in this case.
2015-07-15 13:10:22 +02:00
Zdenek Kabelac
e9e35b011e cache: handle policy_name separately
Keep policy name separate from policy settings and avoid
to mangling and demangling this string from same config tree.
Ensure policy_name is always defined.
2015-07-15 13:10:22 +02:00
Zdenek Kabelac
86a4d47215 cache: move setting of cache policy
Set policy before saving 1st. metadata and avoid unnecessary reload.
Fixes problem when we stored cache-pool without cache-policy set.
2015-07-15 13:10:21 +02:00
Zdenek Kabelac
4a33d57143 thin: fix warning for overprovisioning
When lvm.conf is properly configure for auto resize of overprovisioned
thin-pool volume, avoid showing any warning (2.02.124).
2015-07-15 13:10:21 +02:00
Peter Rajnoha
34a4109946 config: use find_config_tree_array for all arrays
Use find_config_tree_array for all config arrays. Also, add
INTERNAL_ERROR in case there should have been at least default
value defined for a setting but it was not returned for some
reason (either config_settings.h misconfiguration or other config
tree error printed by functions called by find_config_tree_array).
2015-07-15 10:52:23 +02:00
Peter Rajnoha
7e728fe1a1 config: add "defaulting to" message in case we fall back to defaults in find_config_tree_array 2015-07-15 10:50:57 +02:00
David Teigland
96a883a454 metadata: change function name to _allow_extra_system_id
The previous name was misleading since this is not the
primary system_id check, only the "extra" check.
2015-07-14 14:43:16 -05:00
David Teigland
9ab6bdce01 vgchange: fix lock-start filtering and waiting
Both lock_start filters were being skipped when any lock-opt
values were used.  The "auto" lock-opt should cause the
auto_lock_start_list to be used.  The lock_start_list should
always be used.

The behavior of lock_start_list/auto_lock_start_list are tested
and verified to behave like volume_list/auto_activation_volume_list.

Since the default was changed to wait for lock-start to finish,
the "wait" and "autowait" lock-opt values are not needed, but a
new "autonowait" is added to the existing "nowait" avoid the
default waiting.
2015-07-14 14:39:34 -05:00
David Teigland
681f779a3c lockd: fix error message after a failing to get lock
There are two different failure conditions detected in
access_vg_lock_type() that should have different error
messages.  This adds another failure flag so the two
cases can be distinguished to avoid printing a misleading
error message.
2015-07-14 11:36:04 -05:00
Peter Rajnoha
ac3143c093 config: {thin,cache}_{check,repair}_options are never undefined
Require global/{thin,cache}_{check,repair}_options to be always defined.
If not defined directly by user in the configuration and if there's no
concrete default option to use, make "" (empty string) the default one -
it's then clearly visible in the "lvmconfig --type default" (and
generated lvm.conf) and also it makes its handling in the code more
straightforward so we don't need to handle undefined values.

This means, if there are no default values for these settings defined,
we end up with this generated now:
  {thin,cache}_{check,repair}_options = [ "" ]

So the value is never undefined and if it is, it's an error.

(The cache_repair_options is actually not used in the code at the moment,
but once the code using this setting is in, it will follow the same logic
as used for thin_repair_options.)
2015-07-14 10:13:41 +02:00
David Teigland
d41bab4028 man lvmlockd: update method for changing lock type
The old description did not work.
2015-07-13 16:33:58 -05:00
David Teigland
3da88b8917 lockd: allow vgexport and vgimport
The "exported" state of the VG can be useful with lockd VGs
because the exported state keeps a VG from being used in general.
It's a way to keep a VG protected and out of the way.

Also fix the command flags: ALL_VGS_IS_DEFAULT is not true for
vgimport/vgexport, since they both return errors immediately if
no VG args are specified.  LOCKD_VG_SH is not true for vgexport
beause it must use an ex lock to write the VG.
2015-07-13 14:07:57 -05:00
David Teigland
9cfa27f9c5 lockd: allow nolocking and readonly options
When --nolocking is used (by vgs, lvs, pvs):

. don't use lvmlockd at all (set use_lvmlockd to 0)
. allow lockd VGs to be read

When --readonly is used (by vgs, lvs, pvs, vgdisplay, lvdisplay,
pvdisplay, lvmdiskscan, lvscan, pvscan, vgcfgbackup):

. skip actual lvmlockd locking calls
. allow lockd VGs to be read
. check that only shared gl/vg locks are being requested
  (even though the actually locking is being skipped)
. check that no LV locks are requested, because no LVs
  should be activated or used in readonly mode
. disable using lvmetad so VGs are read from disk

It is important to note the limited commands that accept
the --nolocking and --readonly options, i.e. no commands
that change/write a VG or change/activate LVs accept these
options, only commands that read VGs.
2015-07-13 13:15:51 -05:00
David Teigland
c39f3026a8 vgexport: do not allow lockd VG to be exported
vgexport and vgimport have no use for a shared VG.
2015-07-10 15:53:21 -05:00
David Teigland
222bb2b88d lockd: note that external origins don't work in lockd VGs
in a comment at the point where it fails, and in the
lvmlockd man page.
2015-07-10 15:53:21 -05:00
David Teigland
b8538f5dcd vgchange: allow changing to lockd type when mirrors exist
and update lvmlockd man page to reflect the fact that
mirror LVs work correctly in lockd VGs.
2015-07-10 15:53:21 -05:00
David Teigland
c4fdcb04be lvconvert: disallow splitting in lockd VGs
A new lockd lock needs to be created for the new LV
created by split mirror and split snapshot.  Disallow
these options in lockd VGs until that is implemented.
2015-07-10 15:53:21 -05:00
David Teigland
0823511262 lockd: disable part of lock_args validation
There are at least a couple instances where
the lock_args check does not work correctly,
(listed in the comment), so disable the
NULL check for lock_args until those are
resolved.
2015-07-10 15:53:21 -05:00
Marian Csontos
738ae4a77f lvmpolld: Fix segfault on 32 bit architectures
Explicit conversions are needed to align writes and reads on the stack.
int64_t is popped from stack while int was pushed.
2015-07-10 16:16:57 +02:00
Marian Csontos
47ac6a1a2e test: Fix syntax error in prepare_devs 2015-07-10 16:15:15 +02:00
David Teigland
3d2c4dc034 metadata: fix duplicated LV flag
LOCKD_SANLOCK_LV was using the WRITEMOSTLY flag instead of a new one.
2015-07-09 17:02:30 -05:00
David Teigland
082fcc53cc vgchange: fix disallowed LV types in lockd VG
cow snapshots work in lockd VG (they were wrongly
disallowed), but mirror type LVs do not yet work in
lockd VGs (they were wrongly allowed).
2015-07-09 16:34:23 -05:00
David Teigland
074295245b pvcreate: remove recent warning message
log_warn was added recently because no known code used
the given condition, but running pvcreate on an existing
PV uses this case, and should not produce a warning.
2015-07-09 15:26:32 -05:00
David Teigland
cb14bbdbc9 metadata: add comments describing lock_args for lvmlockd 2015-07-09 15:16:28 -05:00
David Teigland
841c3478fd metadata: vg_validate lock_args 2015-07-09 13:25:00 -05:00
David Teigland
6294509cc6 coverity: cleanup related to lvmlockd
A couple missing mutex unlock on error bugs.
A bunch of buffer size/termination warnings.
2015-07-09 11:29:28 -05:00
Peter Rajnoha
1481125042 libdaemon: config_make_nodes_v needs fixing
Put the change from commit #10d27998b3d2f6100e9e29e83d1d99948c55875f
back so we have working tree again for now. This code needs a bit of
a cleanup to return proper return value to check...
2015-07-09 16:34:08 +02:00
Peter Rajnoha
10d27998b3 coverity: missing return value checks 2015-07-09 15:15:15 +02:00
Peter Rajnoha
a9a7c297ae coverity: missing return value for dm_split_lvm_name pass proper DM name instead of NULL value 2015-07-09 13:11:57 +02:00
Peter Rajnoha
023cf21848 coverity: fix possible invalid dereferences
lib/format1/import-export.c:167: var_deref_op: Dereferencing null pointer "vg->lvm1_system_id"
lib/cache/lvmetad.c:1023: var_deref_op: Dereferencing null pointer "this"
daemons/lvmlockd/lvmlockd-core.c:2659: check_after_deref: Null-checking "act" suggests that it may be null, but it has already been dereferenced on all paths leading to the check
/daemons/lvmetad/lvmetad-core.c:1024: check_after_deref: Null-checking "pvmeta" suggests that it may be null, but it has already been dereferenced on all paths leading to the check
2015-07-09 12:07:41 +02:00
Peter Rajnoha
cb305b9fc0 lvmconf: fix ignored --startstopservices in lvmconf ... --mirrorservice on systemd
If running lvmconf ... --startstopservice --mirrorservice in systemd
environment, handle lvm2-cmirrord accordingly. A typo in the script
caused the lvm2-cmirrord to not start/stop immediately, it was
only enabled/disabled (so the --startstopservice was ignored in this
case).
2015-07-09 10:40:14 +02:00
David Teigland
a0cc570f86 vgchange: don't disable VG lock in lock_stop
It was an optimization to avoid a pointless unlock call.
It affects all VGs, but was only intended to affect the
VG being stopped.
2015-07-08 15:26:25 -05:00
David Teigland
903569d533 lvmlockd: remove log_error instances for normal conditions
There are a number of log_error instances that are replaced
by log_debug because they are not errors.
2015-07-08 15:25:14 -05:00
Andy Grover
d77546773b man: add lvmlocal.conf to config cascade
see BZ 1241182, lvmlocal is searched before lvm.conf but after
lvm_<tag>.conf.
2015-07-08 10:02:28 -07:00
David Teigland
de13abdfdf lvmlockd: fix unreachable code 2015-07-08 11:02:11 -05:00
David Teigland
2566bdfbc3 lvmlockctl: fix uninitialized names
When formatting and printing info from lvmlockd.
Also fix some new line problems.
2015-07-08 10:58:56 -05:00
David Teigland
143a9d7ee6 toollib: skip processing the sanlock LV unless named or all
This prevents 'lvremove vgname' from attempting to remove the
hidden sanlock LV.  Only vgremove should remove the hidden
sanlock LV holding the sanlock locks.
2015-07-08 10:27:21 -05:00
Zdenek Kabelac
6e1f421a6d tests: follow symlinks
If the srcdir itself is a symlink the find would not return expected
value. So support also this config and use -L.
2015-07-08 15:41:48 +02:00
Zdenek Kabelac
fd37eeddd6 coverity: fix regresions from 16e9b32c2f
16e9b32c2f incorrectly moved
free of opened descriptor out of if{} - resulted of
closing random file handle.
2015-07-08 15:41:48 +02:00
Peter Rajnoha
6b48233f25 coverity: fix NULL check in lv->lvid.s
tools/polldaemon.c:457: array_null: Comparing an array to null is not useful: "lv->lvid.s"

The lv->lvid.s is never NULL. The check was supposed to be *lv->lvid.s
to check if the string is not empty.
2015-07-08 15:08:39 +02:00
Peter Rajnoha
3ec4813ba2 coverity: fix missing initialization
... Using uninitialized value "lockd_state" when calling "lockd_vg"
(even though lockd_vg assigns 0 to the lockd_state, but it looks at
previous state of lockd_state just before that so we need to have
that properly initialized!)

libdm/libdm-report.c:2934: uninit_use_in_call: Using uninitialized value "tm". Field "tm.tm_gmtoff" is uninitialized when calling "_get_final_time".

daemons/lvmlockd/lvmlockctl.c:273: uninit_use_in_call: Using uninitialized element of array "r_name" when calling "format_info_r_action". (just added FIXME as this looks unfinished?)
2015-07-08 14:53:30 +02:00
Peter Rajnoha
e8dbaf62d3 coverity: previous commit - not "break" but "fall through" 2015-07-08 14:42:31 +02:00
Peter Rajnoha
705fee709f coverity: missing break in switch expression
lib/lvmpolld/lvmpolld-client.c:109: fallthrough: The above case falls through to this one
2015-07-08 14:36:02 +02:00
Peter Rajnoha
71f4fbfbde coverity: fix uninitialized values and other reported problems
daemons/lvmlockd/lvmlockd-core.c:5709: error[uninitStructMember]: Uninitialized struct member: ds.....
daemons/lvmlockd/lvmlockd-core.c:799: error[uninitstring]: Dangerous usage of 'version' (strncpy doesn't always null-terminate it)
daemons/lvmlockd/lvmlockd-core.c:646: error[memleakOnRealloc]: Common realloc mistake: 'pollfd' nulled but not freed upon failure
2015-07-08 14:19:51 +02:00
Peter Rajnoha
16e9b32c2f coverity: fix resource leaks
lib/log/log.c:115: leaked_storage: Variable "st" going out of scope leaks the storage it points to
daemons/lvmpolld/lvmpolld-core.c:573: leaked_storage: Variable "cmdargv" going out of scope leaks the storage it points to
daemons/lvmlockd/lvmlockd-core.c:5341: leaked_handle: Handle variable "fd" going out of scope leaks the handle
daemons/lvmlockd/lvmlockctl.c:575: overwrite_var: Overwriting "able_vg_name" in "able_vg_name = strdup(optarg)" leaks the storage that "able_vg_name" points to
daemons/lvmlockd/lvmlockctl.c:571: overwrite_var: Overwriting "able_vg_name" in "able_vg_name = strdup(optarg)" leaks the storage that "able_vg_name" points to
daemons/lvmlockd/lvmlockctl.c:385: leaked_handle: Handle variable "s" going out of scope leaks the handle
2015-07-08 13:56:06 +02:00
Peter Rajnoha
3b6840e099 config: replace find_config_tree_node with find_config_tree_array where appropriate 2015-07-08 13:03:08 +02:00
Peter Rajnoha
67a61cce1b config: add find_config_tree_array
Before, we used general find_config_tree_node function to retrieve
array values. This had a downside where if the node was not found,
we had to insert default values directly in-situ after the
find_config_tree_node call. This way, we had two copies of default
values - one in config_settings.h and the other one directly in the
code where we found out that find_config_tree_node returned NULL and
hence we needed to fall back to defaults.

With separate find_config_tree_array used for array config values,
we keep all the defaults centrally in config_settings.h because
the new find_config_tree_array automatically returns these defaults
if it can't find any value set in the configuration.

This patch just makes the behaviour exactly the same for arrays as
for any other non-array type where we call find_config_tree_<type>
already, hence making the internal interface for handling array
values consistent with the rest of the config types.
2015-07-08 12:59:22 +02:00
Marian Csontos
d9d47b7b88 spec: Move lvm2-lockd into separate package 2015-07-07 16:53:19 +02:00
Marian Csontos
181e701cc5 spec: Update to use enable_lockd_* 2015-07-07 16:53:19 +02:00
Alasdair G Kergon
a421879bb5 post-release 2015-07-07 13:57:13 +01:00
Alasdair G Kergon
3472910177 pre-release 2015-07-07 13:54:37 +01:00
Ondrej Kozina
088ee7618d lvmpolld: fix possible memory corruption with mem debug
if lvm2 is built with debug memory options dm_free() is not
mapped directly to std library's free(). This may cause memory corruption
as a line buffer may get reallocated in getline with realloc.

This is a temporary hotfix. Other debug memory failure needs to
be investigated and explained.
2015-07-07 14:49:53 +02:00
Peter Rajnoha
a405b89555 conf: regenerate 2015-07-07 14:27:00 +02:00
Alasdair G Kergon
88760141da WHATS_NEW: Update. Fix renamed config setting vsn. 2015-07-07 13:20:01 +01:00
Peter Rajnoha
b174c27d4d conf: regenerate 2015-07-07 14:11:16 +02:00
Zdenek Kabelac
bfd0689d64 tests: use old snapshot for huge volumes
Avoid stacking thins over thins.
2015-07-07 09:57:32 +02:00
Zdenek Kabelac
0ac20a8fdb cache: support clear-needs-check
Support newer cache tool which support new option
--clear-needs-check-flag.

Code does same as for thin_check.
2015-07-07 09:57:27 +02:00
David Teigland
d16332be72 lvmetactl: program to interact with lvmetad
This is not installed; it's only a developer utility
at this point.
2015-07-06 15:54:22 -05:00
David Teigland
6a8cc1dcd4 man lvmlockd: minor updates 2015-07-06 15:32:41 -05:00
Alasdair G Kergon
c923dee8de configure: Separate sanlock and dlm lock config. 2015-07-06 18:20:20 +01:00
David Teigland
633aea92fb config: remove read_only_lock_modes
It had been added as part of lvmlockd code, but it does
not seem particularly useful.
2015-07-06 11:44:28 -05:00
David Teigland
e1733a6271 lockd: remove unused code for overriding lock modes
including the allow_override_lock_modes setting.

It was not possible to override default lock modes any longer,
since the command line options had already been removed.

A mechanism will probably be required later that puts part of
this back.
2015-07-06 11:44:28 -05:00
David Teigland
114744cee1 config: rename lock_retries lvmlockd_lock_retries
Because it only applies to lvmlockd requests, but
sounded too general.
2015-07-06 11:44:28 -05:00
Alasdair G Kergon
dfe3eb12d0 include: Standardise around new tool.h. 2015-07-06 17:30:18 +01:00
David Teigland
d3605b81f3 configure: enable building lvmlockd without sanlock or dlm 2015-07-06 11:09:58 -05:00
Jonathan Brassow
4daea88516 clean-up: typos s/bellow/below/ 2015-07-06 10:15:11 -05:00
Alasdair G Kergon
810ab095e6 macros: Wrap PRI with FMT.
Create a set of wrappers with embedded % such as
  #define FMTu64 "%" PRIu64
2015-07-06 15:09:17 +01:00
Marian Csontos
5fb71bd530 lockd: Clean up spec 2015-07-04 14:36:57 +02:00
Marian Csontos
dd385eb5ac Build lockd only for Fedora >= 22 and RHEL >= 7 2015-07-04 14:36:57 +02:00
Alasdair G Kergon
b4e8de3a31 post-release 2015-07-03 16:58:24 +01:00
Alasdair G Kergon
36ce97c625 pre-release 2015-07-03 16:34:40 +01:00
Zdenek Kabelac
3dbb9a57ca tests: update for new thin pool messaging 2015-07-03 16:13:15 +02:00
Zdenek Kabelac
a900d150e4 thin: move pool messaging from resume to suspend
Existing messaging intarface for thin-pool has a few 'weak' points:

* Message were posted with each 'resume' operation, thus not allowing
activation of thin-pool with the existing state.

* Acceleration skipped suspend step has not worked in cluster,
since clvmd resumes only nodes which are suspended (have proper lock
state).

* Resume may fail and code is not really designed to 'fail' in this
phase (generic rule here is resume DOES NOT fail unless something serious
is wrong and lvm2 tool usually doesn't handle recovery path in this case.)

* Full thin-pool suspend happened, when taken a thin-volume snapshot.

With this patch the new method relocates message passing into suspend
state.

This has a few drawbacks with current API, but overal it performs
better and gives are more posibilities to deal with errors.

Patch introduces a new logic for 'origin-only' suspend of thin-pool and
this also relates to thin-volume when taking snapshot.

When suspend_origin_only operation is invoked on a pool with
queued messages then only those messages are posted to thin-pool and
actual suspend of thin pool and data and metadata volume is skipped.

This makes taking a snapshot of thin-volume lighter operation and
avoids blocking of other unrelated active thin volumes.

Also fail now happens in 'suspend' state where the 'Fail' is more expected
and it is better handled through error paths.

Activation of thin-pool is now not sending any message and leaves upto a tool
to decided later how to finish unfinished double-commit transaction.

Problem which needs some API improvements relates to the lvm2 tree
construction. For the suspend tree we do not add target table line
into the tree, but only a device is inserted into a tree.
Current mechanism to attach messages for thin-pool requires the libdm
to know about thin-pool target, so lvm2 currently takes assumption, node
is really a thin-pool and fills in the table line for this node (which
should be ensured by the PRELOAD phase, but it's a misuse of internal API)
we would possibly need to be able to attach message to 'any' node.

Other thing to notice - current messaging interface in thin-pool
target requires to suspend thin volume origin first and then send
a create message, but this could not have any 'nice' solution on lvm2
side and IMHO we should introduce something like 'create_after_resume'
message.

Patch also changes the moment, where lvm2 transaction id is increased.
Now it happens only after successful finish of kernel transaction id
change. This change was needed to handle properly activation of pool,
which is in the middle of unfinished transaction, and also this corrects
usage of thin-pool by external apps like Docker.
2015-07-03 16:13:14 +02:00
Zdenek Kabelac
5bef18f2eb libdm: support for posting messages in suspend
Add support for sending message in suspend tree for thin-pools.
When this operation is requested whole subtree suspend is then skipped.

This is experimantal support for new lvm2 code for sending message
in suspend phase where 'thin-pool origin-only suspend' will send
messages instead of really suspending thin-pool tree.

When suspening thin volume origin-only - only thin volume is suspended,
then messages are posted and thin-pool suspend is skipped.
2015-07-03 16:13:14 +02:00
Zdenek Kabelac
622064f00f thin: check for overprovisioning 2015-07-03 16:13:14 +02:00
Peter Rajnoha
9cee94372a report: select: add handler to recognize fuzzy time specification
Recognize date and time specification within selection criteria
that is formulated in a more free-form way besides to the original
basic YYYY-MM-DD HH:MM format that libdevmapper supports.

Currently, this free-form format is recognized for lv_time field.

Users are able to use expressions from this set:
  - weekday names ("Sunday" - "Saturday" or abbreviated as "Sun" - "Sat")
  - labels for points in time ("noon", "midnight")
  - labels for a day relative to current day ("today", "yesterday")
  - points back in time with relative offset from today (N is a number)
    ( "N" "seconds"/"minutes"/"hours"/"days"/"weeks"/"years" "ago")
    ( "N" "secs"/"mins"/"hrs" ... "ago")
    ( "N" "s"/"m"/"h" ... "ago")
  - time specification either in hh:mm:ss format or with AM/PM suffixes
  - month names ("January" - "December" or abbreviated as "Jan" - "Dec")

For example:

$ date
Fri Jul  3 10:11:13 CEST 2015

$ lvmconfig --type full report/time_format
time_format="%a %Y-%m-%d %T %z %Z [%s]"

$ lvs
  LV    VG     Time
  lvol0 vg     Fri 2014-08-22 21:25:41 +0200 CEST [1408735541]
  lvol2 vg     Sun 2015-04-26 14:52:20 +0200 CEST [1430052740]
  root  fedora Wed 2015-05-27 08:09:21 +0200 CEST [1432706961]
  swap  fedora Wed 2015-05-27 08:09:21 +0200 CEST [1432706961]
  lvol1 vg     Tue 2015-06-30 03:25:43 +0200 CEST [1435627543]
  lvol3 vg     Tue 2015-06-30 14:52:23 +0200 CEST [1435668743]
  lvol6 vg     Wed 2015-07-01 13:35:56 +0200 CEST [1435750556]
  lvol4 vg     Thu 2015-07-02 12:12:02 +0200 CEST [1435831922]
  lvol5 vg     Thu 2015-07-02 14:30:32 +0200 CEST [1435840232]

$ lvs -S 'time=yesterday'
  LV    VG   Time
  lvol4 vg   Thu 2015-07-02 12:12:02 +0200 CEST [1435831922]
  lvol5 vg   Thu 2015-07-02 14:30:32 +0200 CEST [1435840232]

$ lvs -S 'time since "June 30"'
  LV    VG   Time
  lvol1 vg   Tue 2015-06-30 03:25:43 +0200 CEST [1435627543]
  lvol3 vg   Tue 2015-06-30 14:52:23 +0200 CEST [1435668743]
  lvol6 vg   Wed 2015-07-01 13:35:56 +0200 CEST [1435750556]
  lvol4 vg   Thu 2015-07-02 12:12:02 +0200 CEST [1435831922]
  lvol5 vg   Thu 2015-07-02 14:30:32 +0200 CEST [1435840232]

$ lvs -S 'time since "noon June 30"'
  LV    VG   Time
  lvol3 vg   Tue 2015-06-30 14:52:23 +0200 CEST [1435668743]
  lvol6 vg   Wed 2015-07-01 13:35:56 +0200 CEST [1435750556]
  lvol4 vg   Thu 2015-07-02 12:12:02 +0200 CEST [1435831922]
  lvol5 vg   Thu 2015-07-02 14:30:32 +0200 CEST [1435840232]

$ lvs -S 'time since "2 July 9AM"'
  LV    VG   Time
  lvol4 vg   Thu 2015-07-02 12:12:02 +0200 CEST [1435831922]
  lvol5 vg   Thu 2015-07-02 14:30:32 +0200 CEST [1435840232]

$ lvs -S 'time since "2 July 1PM"'
  LV    VG   Time
  lvol5 vg   Thu 2015-07-02 14:30:32 +0200 CEST [1435840232]

...and so on.
2015-07-03 10:51:31 +02:00
Peter Rajnoha
3b1422c45c report: call appropriate handler to evaluate fuzzy reserved names and dynamic reserved values
Wire the dm_report_reserved_handler instance call in reporting/selection
infrastructure to handle reserved value actions (currently only
DM_REPORT_RESERVED_PARSE_FUZZY_NAME and DM_REPORT_RESERVED_GET_DYNAMIC_VALUE
actions).
2015-07-03 10:47:38 +02:00
Peter Rajnoha
335707b0e2 report: add infrastructure to recognize fuzzy reserved names and returning dynamic reserved values
With fuzzy names we mean the names for which it's hard or even impossible
to enumerate all possible variations of the name - the name needs to
be evaluated. An example of fuzzy name is a name which has a base
(substring) which matches and it can contain arbitrary variations
around this base. We can cover human language better with fuzzy
names as people may use several different names (or sentences) to
denote the same thing.

With dynamic values we mean the values which are not constants
and they need to be evaluated in runtime. An example of dynamic
value is a value which depends on current system state (e.g. time,
current configuration or any other state which may change and it
needs runtime evaluation).

There's a handler that can be registered with reporting/selection
using dm_report_reserved_handler instance. This is a central point
in which the computation/evaluation happens when processing reserved
values. Currently, there are two actions declared:

  DM_REPORT_RESERVED_PARSE_FUZZY_NAME
  (translates fuzzy name into canonical name)

  DM_REPORT_RESERVED_GET_DYNAMIC_VALUE
  (gets value for canonical name)

The handler is then registered as value in struct
dm_report_reserved_value (see explaining comments besided
the struct dm_report_reserved_value in libdevmapper.h).

Also, this patch provides support for simple caching of values
used during report/selection via dm_report_value_cache_{set,get}.
This is supposed to be used mainly in the dm_report_reserved_handler
instances to save values among calls so all the handler calls work
with the same base value used in computation/evaluation and/or
possibly to save resources if the evaluation is more time-consuming.
The cache is attached to the dm_report handle and so the cache is
dropped one dm_report is dropped.
2015-07-03 10:47:09 +02:00
Peter Rajnoha
82ecfa6f0e cleanup: commit fe70b03 turned lv_time to STR, put it back to TIM 2015-07-03 09:22:48 +02:00
David Teigland
e944a9c635 lockd: fix stub functions for LV locking
The stub functions for lockd LV locking were returning
the wrong result when lvm was compiled without lvmlockd.
2015-07-02 16:36:04 -05:00
David Teigland
fe70b03de2 Add lvmlockd 2015-07-02 15:42:26 -05:00
Peter Rajnoha
a32d5a4afc report: adjust shared flags based on expected type for reserved values
Generic numbers and time values share some operators so make sure
we have the flags correctly adjusted based on expected type if
we're using reserved values.
2015-07-02 16:12:01 +02:00
Peter Rajnoha
eaa0d927a4 tests: add test for 454782f (select with synonyms for string field types) 2015-07-02 11:46:58 +02:00
Peter Rajnoha
454782f1a3 report: fix regression while selecting string fields using synonyms
$ lvs -o name,cache_policy vg/lvol0
  LV    Cache Policy
  lvol0

Before this patch:
$ lvs -o name,cache_policy -S 'cache_policy=undefined' vg/lvol0
  (no match)

With this patch applied:
$ lvs -o name,cache_policy -S 'cache_policy=undefined' vg/lvol0
  LV    Cache Policy
  lvol0
2015-07-02 11:31:54 +02:00
Zdenek Kabelac
7f63fff9c4 display: missed to count with 0
dm_snprintf() returns upon success the number of characters printed
(excluding the null byte used to end output to strings).

So add extra byte to preserve \0.
This fixes regression when displaying more then a single lv name.
2015-07-02 00:10:38 +02:00
Zdenek Kabelac
21c0b1134f libdm: enhance tracing messages
Use new _node_name() and print name major:minor for thin-pool device.
2015-07-01 13:44:28 +02:00
Zdenek Kabelac
04ae5007e3 libdm: add helper function to print _node_name
_node_name() prepares into dm_tree internal buffer device
name and it (major:minor) for easy usage for debug messages.

To avoid any allocation a small buffer in struct dm_tree is preallocated
to store this message.
2015-07-01 13:41:40 +02:00
Peter Rajnoha
a69ded43b0 config: report/time_format appeared in v2.02.123 2015-07-01 08:20:20 +02:00
Alasdair G Kergon
4c629a5257 locking: Add missing error handling.
Add missing error logging and detection to unlock_vg and callers
of sync_local_dev_names etc.
2015-06-30 18:54:38 +01:00
Alasdair G Kergon
3489e68ef7 post-release 2015-06-30 17:12:56 +01:00
Alasdair G Kergon
a3af8b0626 pre-release 2015-06-30 17:11:21 +01:00
Alasdair G Kergon
92138badd4 conf: Regenerate.
Fix missing --clear-needs-check-flag.
2015-06-30 17:09:56 +01:00
Alasdair G Kergon
f6ad48f0e5 libdm: Rename struct time_value variables.
warning: declaration of ‘time’ shadows a global declaration
2015-06-30 16:17:22 +01:00
Peter Rajnoha
ded279f826 report: add support for time (basic)
This patch adds support for time values used in reporting fields.
The raw values are always stored as number of seconds since epoch.

The support that comes with this patch is the basic one which allows
only for recognition of strictly formatted date and time in selection
criteria (the format follows a subset of formats defined by ISO 8601):

  date time timezone

  date:
    YYYY-MM-DD (or shortly YYYYMMDD)
    YYYY-MM (shortly YYYYMM), auto DD=1
    YYYY, auto MM=01 and DD=01

  time:
    hh:mm:ss (or shortly hhmmss)
    hh:mm (or shortly hhmm), auto ss=0
    hh (or shortly hh), auto mm=0, auto ss=0

  timezone (always with + or - sign):
    +hh:mm or -hh:mm (or shortly +hhmm or -hhmm)
    +hh or -hh

Or directly the time (number of seconds) since Epoch (1970-01-01 00:00:00 UTC)
when the number value is prefixed by "@":

   @number_of_seconds_since_epoch

This patch also adds aliases for comparison operators
used together with time values which are more intuitive
to use:
  since (as alias for >=)
  after (as alias for >)
  until (as alias for <=)
  before (as alias for <)

For example:

$ lvmconfig --type full report/time_format
time_format="%Y-%m-%d %T %z %Z [%s]"

$ lvs -o name,time vg
  LV    Time
  lvol0 2015-06-28 21:25:41 +0200 CEST [1435519541]
  lvol1 2015-06-30 03:25:43 +0200 CEST [1435627543]
  lvol2 2015-04-26 14:52:20 +0200 CEST [1430052740]
  lvol3 2015-06-30 14:52:23 +0200 CEST [1435668743]

$ lvs vg -o name,time -S 'time since "2015-04-26 15:00" && time until "2015-06-30"'
  LV    Time
  lvol0 2015-06-28 21:25:41 +0200 CEST [1435519541]
  lvol1 2015-06-30 03:25:43 +0200 CEST [1435627543]
  lvol3 2015-06-30 14:52:23 +0200 CEST [1435668743]

$ lvs vg -o name,time -S 'time since "2015-04-26 15:00" && time until "2015-06-30 6:00"'
  LV    Time
  lvol0 2015-06-28 21:25:41 +0200 CEST [1435519541]
  lvol1 2015-06-30 03:25:43 +0200 CEST [1435627543]

$ lvs vg -o name,time -S 'time since @1435519541'
  LV    Time
  lvol0 2015-06-28 21:25:41 +0200 CEST [1435519541]
  lvol1 2015-06-30 03:25:43 +0200 CEST [1435627543]
  lvol3 2015-06-30 14:52:23 +0200 CEST [1435668743]

This is basic time recognition support that is directly a part of
libdevmapper. Recognition of more free-form expressions will be a
part of subsequent patches.
2015-06-30 15:15:10 +02:00
Peter Rajnoha
89d355ea04 configure: set DEFAULT_FALLBACK_TO_LVM1 in configure and use it in config_settings.h
Just like we have DEFAULT_USE_LVMETAD (or DEFUALT_USE_LVMPOLLD), use
fallback_to_lvm1=1 lvm.conf setting if we configured lvm2 with
--enable-lvm1-fallback and use fallback_to_lvm1=0 otherwise.

Also, generate proper lvm.conf.in with unconfigured value.
2015-06-30 14:09:05 +02:00
Peter Rajnoha
d7b9349ce7 cleanup: report: use internal wrapper for various variables used for handling reserved values
Just a cleanup - wrap several variables we use to handle reserved
values into a structure for easier manipulation in the code.
2015-06-30 10:47:51 +02:00
Peter Rajnoha
d8996a17d1 select: add support for range reserved values and flagging named-only values
This patch allows for registration and recognition of reserved
values which are ranges, so they're composed of two values actually
to denote the lower and upper bound for the range (stored as an array
with exactly two items to define the boundaries).

Also, this patch allows for flagging reserved values as named-only
which means that such values are not strictly reserved. The strictly
reserved values are reserved values as used before this patch.

Distinction between strictly-reserved and named-only values
is clearly visible with comparisons. Normally, strictly reserved
value is not accounted for if we do "greater than" or "lower than"
comparisons, for example:

1  2  3 ....
   |
  abc

- we have "abc" as reserved value for field with value "2"
- the value reported for the field is "abc" (or "2", it doesn't matter here)
- the selection we're processing is -S 'field < abc'
- the result of the selection gives nothing as "abc" is strictly
reserved value (bound to "2") and there's no order defined for
it and it would only match if we directly compared the value
(so -S 'field = abc' would match)

With named-only values, the "abc" is named-only value for "2",
so selection -S 'field < abc" is the same as using -S 'field < 2'.
The "abc" is just an alias for some value so the value or its
assigned name can be used equally in selection criteria.
2015-06-30 10:47:50 +02:00
Peter Rajnoha
77f0e7a450 cleanup: time: error out on incorrect time_format and indentation in config_settings.h 2015-06-29 16:17:33 +02:00
Peter Rajnoha
621398ebb7 lv: time: increase buffer to 4k in lv_time_dup 2015-06-29 15:24:00 +02:00
Peter Rajnoha
1587236089 toolcontext: use proper set of chars to check time format against 2015-06-29 14:45:53 +02:00
Peter Rajnoha
125cd06698 conf: make time format configurable
Make it possible to define format for time that is displayed.
The way the format is defined is equal to the way that is used
for strftime function, although not all formatting options as
used in strftime are available for LVM2 - the set is restricted
(e.g. we do not allow newline to be printed). The lvm.conf
comments contain the whole list that LVM2 accepts for time format
together with brief description (copied from strftime man page).

For example:
(defaults used - the format is the same as used before this patch)
$ lvs -o+time vg/lvol0 vg/lvol1
  LV    VG   Attr       LSize Time
  lvol0 vg   -wi-a----- 4.00m 2015-06-25 16:18:34 +0200
  lvol1 vg   -wi-a----- 4.00m 2015-06-29 09:17:11 +0200

(using 'time_format = "@%s"' in lvm.conf - number of seconds
since the Epoch)
$ lvs -o+time vg/lvol0 vg/lvol1
  LV    VG   Attr       LSize Time
  lvol0 vg   -wi-a----- 4.00m @1435241914
  lvol1 vg   -wi-a----- 4.00m @1435562231
2015-06-29 14:30:35 +02:00
Peter Rajnoha
6f793d34ca config: regenerate lvm.conf.in and lvmlocal.conf.in 2015-06-29 13:43:28 +02:00
Peter Rajnoha
7b45a1fc60 refactor: rename _out_tags fn to _out_list and use it for string lists in general 2015-06-29 09:43:55 +02:00
Peter Rajnoha
f143ad3a93 cleanup: remove unused tags.c file 2015-06-29 09:43:47 +02:00
Peter Rajnoha
e29d4773f4 refactor: rename alloc_printed_tags fn to _alloc_printed_str_list and use it for string lists in general 2015-06-29 09:43:41 +02:00
Peter Rajnoha
77c2d11657 refactor: rename read_tags fn to _read_str_list and use it for string lists in general 2015-06-29 09:43:32 +02:00
Zdenek Kabelac
02767c5eb1 tests: tests needs pre 1.13 thin-pool extorg
This test is testing older style, so disable feature when present.
2015-06-26 22:16:01 +02:00
Zdenek Kabelac
03c4fee5a7 tests: deactivate before remove
Testing if this avoids udev race with removal of snapshot on some
test machines.
See: https://bugzilla.redhat.com/show_bug.cgi?id=1217819
2015-06-26 22:11:46 +02:00
Ferenc Wágner
a62cd64db6 makefiles: avoid bash == operator syntax, use = instead
Commit e587b0677b broke the build on
systems where /bin/sh is Dash, for example.

Origin patch by Ferenc Wágner <wferi@niif.hu>  changed later to
avoid using shell call, so makefile add 'server' target when
one of  metad or polld daemon is requested.
2015-06-26 22:11:45 +02:00
Peter Rajnoha
844707067b lvmconfig: do not display settings with undefined default values
Do not display settings with undefined default values, but do display
these settings in case the value is defined directly in any part of
the existing config cascade.

For example, the lvmconfig --type current always displays these settings
(as it's somewhere in "current" configuration cascade that makes it defined).
The lvmconfig --type full displays these settings only if it's defined
somewhere in the cascade, but not if default value is used instead
The lvmconfig --type default never displays these settings...

More concrete example - let's have activation/volume_list directly
set in lvm.conf and activation/read_only_volume_list not set.
Both of these settings have *undefined default* values.

  $lvmconfig --type full activation/volume_list activation/read_only_volume_list
  volume_list="/dev/vg/lv"

(...only volume_list is defined, hence it's printed)

However, the comments will display more info (see also previous commit):

  $lvmconfig --type full activation/volume_list activation/read_only_volume_list --withsummary

  # Configuration option activation/volume_list.
  # Only LVs selected by this list are activated.
  # This configuration option does not have a default value defined.
  # Value defined in existing configuration has been used for this setting.
  volume_list="/dev/vg/lv"

  # Configuration option activation/read_only_volume_list.
  # LVs in this list are activated in read-only mode.
  # This configuration option does not have a default value defined.
2015-06-25 13:51:55 +02:00
Peter Rajnoha
07a34184db lvmconfig: display comment about value from existing config being used
Display comment abour value from existing config being used. For example:

$ lvmconfig --type full --withsummary report/compact_output report/buffered

 # Configuration option report/compact_output.
 # Do not print empty report fields.
 # Value defined in existing configuration has been used for this setting.
 compact_output=1

 # Configuration option report/buffered.
 # Buffer report output.
 buffered=1
2015-06-25 13:51:54 +02:00
Peter Rajnoha
c794c163b5 lvmconfig: add --type full to display full tree of settings
The lvmconfig --type full is actually a combination of --type current
and --type missing together with --mergedconfig options used.

The overall outcome is a configuration tree with settings as LVM sees
it when it looks for the values - that means, if the setting is defined
in some config source (lvm.conf, --config, lvmlocal.conf or any profile
that is used), the setting is used. Otherwise, if the setting is not
defined in any part of the config cascade, the defaults are used.

The --type full displays exactly this final tree with all the values
defined, either coming from configuration tree or from defaults.
2015-06-25 13:33:52 +02:00
Peter Rajnoha
f6de196c21 config: also clone associated id when cloning node using dm_config_clone_node{_with_mem} 2015-06-25 10:21:07 +02:00
Alasdair G Kergon
110a0745cd man: Add missing env vars to lvm man page. 2015-06-24 20:43:35 +01:00
David Teigland
7760665fb8 libdaemon: add comment about using main and init 2015-06-24 12:16:26 -05:00
Zdenek Kabelac
44c7bc0262 tests: workaround udev problem
If udev has not removed 'dir' entry - just issue TEST WARNING, clear
dir, but do not fail whole rest of test.
2015-06-24 15:19:53 +02:00
Zdenek Kabelac
e217873ed6 snapshot: add synchronization point
Synchronize with udev logic before reusing device as snapshot.

This patch tries to fix the problem with udev, where we manage
to 'active' LV for clearing, then we deactivate such device and
active again as member of 'origin&snapshot' tree all in 1 step.

There needs to be a sync point where udev has time to remove all links,
otherwise we race with scans and we may end-up with mysterious 'free'
links in the system pointing to wrong dm names.

This patch tries to fix failing topology cluster tests..
2015-06-24 15:18:49 +02:00
Peter Rajnoha
cf189a572a commands: --withspaces also for config and lvmconfig cmd aliases 2015-06-24 13:28:40 +02:00
Peter Rajnoha
7559d871fb make: use lvmconfig ... --withspaces when generating lvm.conf and lvmlocal.conf 2015-06-24 13:20:38 +02:00
Peter Rajnoha
a4724350e4 lvmconfig: add --withspaces option
We shouldn't be adding spaces by default in output as that
may be be used already in scripts and especially for the eval
in shell scripts where spaces are not allowed between key
and value!

Add --withspaces option to lvmconfig for pretty output with
more space in for readability.
2015-06-24 13:19:23 +02:00
Peter Rajnoha
a25d92c88b WHATS_NEW: recent commits - config value format flags 2015-06-24 11:34:02 +02:00
Peter Rajnoha
982cf44ff0 config: regenerate configure.in to accomodate all recent changes
Hopefully closer to the ideal.
2015-06-24 11:24:10 +02:00
Peter Rajnoha
63c5aaaaf2 config: devices/filter and devices/global_filter setting have 'a/.*/' as default value 2015-06-24 11:23:54 +02:00
Peter Rajnoha
c725648f6c config: allow empty values for {thin,cache}_{check,repair}_options
It's not an error to define empty values for
{thin,cache}_{check,repair}_options - such empty value means no
options are passed when these external commands are called.
2015-06-24 11:13:38 +02:00
Peter Rajnoha
20e336f21c configure: add DEFAULT_USE_BLKID_WIPING
If blkid wiping is possible, than set use_blkid_wiping=1 and
use_blkid_wiping=0 otherwise for its default value. If blkid wiping
is disabled during configure and use_blkid_wiping=1 is set by chance,
it's simply ignored - this patch is just a cleanup that makes it more
obvious for the user (we use similar logic for use_lvmetad and
use_lvmpolld settings).
2015-06-24 11:13:38 +02:00
Peter Rajnoha
6575122c63 config: display global/umask in octal form 2015-06-24 11:13:38 +02:00
Peter Rajnoha
74bf75a2f5 config: use proper unconfigured default values for use_lvmetad and use_lvmpolld settings
Default value for lvmetad and lvmpolld has hooks in configure script,
the "lvmconfig --type default --unconfigured" should display:

   use_lvmetad = @DEFAULT_USE_LVMETAD@
   use_lvmpolld = @DEFAULT_USE_LVMPOLLD@

Note that these settings are not of string type. Recent change (the
DM_CONFIG_VALUE_FMT_STRING_NO_QUOTES formatting flag) makes it
possible to recognize that the setting is not of string type and if
there's unconfigured value defined for it, the enclosing " " is
automatically removed on output.
2015-06-24 11:13:38 +02:00
Peter Rajnoha
1545ebf938 config: cleanup default values for some configuration settings with array values
Do not use "#S" (blank string) as default value as that ends up with
'key = [ "" ]' to be generated which is not what we want in most cases.

Also, fix default values for global/{thin,cache}_{check,repair}_options
and avoid assigning blank values. For example, the thin_check_options
had this set as default value previously:

  "#S" DEFAULT_THIN_CHECK_OPTION1 "#S" DEFAULT_THIN_CHECK_OPTION2

If any (or both) of DEFAULT_THIN_CHECK_OPTION* variables was set
to "", we ended up with clumsy default value generated like:

  thin_check_options = [ "-q", "" ]

With this patch, we end up with correct:

  thin_check_options = [ "-q" ]

or, if all options are undefined:

  thin_check_options = [ ]

Which is the correct way to express this.
2015-06-24 11:13:38 +02:00
Peter Rajnoha
9465963faf config: add support for config value formatting flags
There are two basic groups of formatting flags (32 bits):
  - common ones applicable for all config value types (lower 16 bits)
  - type-related formatting flags (higher 16 bits)

With this patch, we initially support four new flags that
modify the the way the config value is displayed:

  Common flags:
  =============

  DM_CONFIG_VALUE_FMT_COMMON_ARRAY - causes array config values
    to be enclosed in "[ ]" even if there's only one item
    (previously, there was no way to recognize an array with one
     item and scalar value, hence array values with one member
     were always displayed without "[ ]" which libdm accepted
     when reading, but it may have been misleading for users)

  DM_CONFIG_VALUE_FMT_COMMON_EXTRA_SPACE - causes extra spaces to
    be inserted in "key = value" (or key = [ value, value, ... ] in
    case of arrays), compared to "key=value" seen on output before.
    This makes the output more readable for users.

  Type-related flags:
  ===================

  DM_CONFIG_VALUE_FMT_INT_OCTAL - prints integers in octal form with
    "0" as a prefix (libdm's config reading code can handle this via
    strtol just fine so it's properly recognized as number in octal
    form already if there's "0" used as prefix)

  DM_CONFIG_VALUE_FMT_STRING_NO_QUOTES - makes it possible to print
    strings without enclosing " "

This patch also adds dm_config_value_set_format_flags and
dm_config_value_get_format_flags functions to set and get
these formatting flags.
2015-06-24 11:13:37 +02:00
David Teigland
c5ba60827e libdaemon: allow main processing function to be specified 2015-06-23 16:55:45 -05:00
David Teigland
ba2b701f2c doc: mention new invalid states in lvmetad_design 2015-06-23 16:48:28 -05:00
David Teigland
c23e7ff2a0 Reread global state the lvmetad copy is stale
This is the client side handling of the global_invalid state
added to lvmetad in commit c595b50cec8a6b95c6ac4988912d1412f3cc0237.

The function added here:
. checks if the global state in lvmetad is invalid
. if so, scans disks to update the state in lvmetad
. clears the global_invalid flag in lvmetad
. updates the local udev db to reflect any changes
2015-06-23 16:36:40 -05:00
David Teigland
679b6b5b29 Reread a VG if the lvmetad copy is stale
and update the lvmetad copy after it is reread from disk.

This is the client side handling of the vg_invalid state
added to lvmetad in commit c595b50cec8a6b95c6ac4988912d1412f3cc0237.
2015-06-23 16:36:40 -05:00
David Teigland
bf77f71711 lvmetad: add invalidation method
Add the ability to invalidate global or individual VG metadata.
The invalid state is returned to lvm commands along with the metadata.
This allows lvm commands to detect stale metadata from the cache and
reread the latest metadata from disk (in a subsequent patch.)

These changes do not change the protocol or compatibility between
lvm commands and lvmetad.

Global information
------------------

Global information refers to metadata that is not isolated
to a single VG , e.g. the list of vg names, or the list of pvs.

When an external system, e.g. a locking system, detects that global
information has been changed from another host (e.g. a new vg has been
created) it sends lvmetad the message: set_global_info: global_invalid=1.
lvmetad sets the global invalid flag to indicate that its cached data is
stale.

When lvm commands request information from lvmetad, lvmetad returns the
cached information, along with an additional top-level config node called
"global_invalid".  This new info tells the lvm command that the cached
information is stale.

When an lvm command sees global_invalid from lvmated, it knows it should
rescan devices and update lvmetad with the latest information.  When this
is complete, it sends lvmetad the message: set_global_info:
global_invalid=0, and lvmetad clears the global invalid flag.  Further lvm
commands will use the lvmetad cache until it is invalidated again.

The most common commands that cause global invalidation are vgcreate and
vgextend.  These are uncommon compared to commands that report global
information, e.g. vgs.  So, the percentage of lvmetad replies containing
global_invalid should be very small.

VG information
--------------

VG information refers to metadata that is isolated to a single VG,
e.g. an LV or the size of an LV.

When an external system determines that VG information has been changed
from another host (e.g. an lvcreate or lvresize), it sends lvmetad the
message: set_vg_info: uuid=X version=N.  X is the VG uuid, and N is the
latest VG seqno that was written.  lvmetad checks the seqno of its cached
VG, and if the version from the message is newer, it sets an invalid flag
for the cached VG.  The invalid flag, along with the newer seqno are saved
in a new vg_info struct.

When lvm commands request VG metadata from lvmetad, lvmetad includes the
invalid flag along with the VG metadata.  The lvm command checks for this
flag, and rereads the VG from disk if set.  The VG read from disk is sent
to lvmetad.  lvmetad sees that the seqno in the new version matches the
seqno from the last set_vg_info message, and clears the vg invalid flag.
Further lvm commands will use the VG metadata from lvmetad until it is
next invalidated.
2015-06-23 16:36:33 -05:00
Zdenek Kabelac
4c6b3f5ec3 tests: use vgscan after enable_dev
Since our test environment runs also in non-real-udev world,
it's using  /etc/.cache file with scanned files.

So in this case it is mandatory the user runs 'vgscan'
after a device reappears in the system.

This 'first' lvm2 command then fixes metadata (just like vgs did).
2015-06-23 13:39:57 +02:00
Zdenek Kabelac
ae76e8f0d0 tests: skip when snapshot does not work
Some older kernel (i.e. 3.11.10 on fc20) do not work properly.
Skip the test if snapshot does not meet 50%.
2015-06-23 13:25:09 +02:00
Zdenek Kabelac
7ee3ccd826 tests: newer version needed for ext-orig 2015-06-23 11:56:42 +02:00
Zdenek Kabelac
9c86d33e68 cleanup: avoid printing gcc warning
Casting to (void) with gcc doesn't remove unused_result warning.
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25509
2015-06-23 11:06:02 +02:00
Alasdair G Kergon
50d70eff35 post-release 2015-06-20 01:05:21 +01:00
Alasdair G Kergon
134b727b4f pre-release 2015-06-20 00:57:35 +01:00
Zdenek Kabelac
b45e9183bc tests: external origin updates
Update test for recent updates to support unalligned sizes
and extension of reduced volume.
2015-06-19 16:33:29 +02:00
Zdenek Kabelac
00d028fd77 log: flush stdout before print to stderr
Keep logging readable and fflush stdout before printing to stderr.
2015-06-19 16:33:20 +02:00
Zdenek Kabelac
3173442984 lvm: move hyphen mangling code
Relocate hyphen code from lvm main into lvm_run_command()
so all command and library user will have it.

Update WHATS_NEW with missing changes.
2015-06-19 09:51:48 +02:00
Zdenek Kabelac
438a65dfdb display: drop allocation from display_lvname
Use of display_lvname() in plain log_debug() may accumulate memory in
command context mempool. Use instead small ringbuffer which allows to
store cuple (10 ATM) names so upto 10 full names can be used at one.

We are not keeping full VG/LV names as it may eventually consume larger
amount of RAM resouces if vgname is longer and lots of LVs are in use.

Note: if there would be ever needed for displaing more names at once,
the limit should be raised (e.g. log_debug() would need to print more
then 10 LVs on a single line).
2015-06-18 18:50:37 +02:00
Zdenek Kabelac
a3e0d830bd thin: support unaligned size of external origin and thin pool
With thin-pool kernel target module 1.13 it's now support usage of
external origin with sizes which are not 'alligned' with chunk size
of thin-pool.

Enable lvm2 support for this and also fix reporting of data_percent
usage for case sizes are not alligned.
2015-06-18 18:50:36 +02:00
Zdenek Kabelac
6f2a617c31 thin: drop limitation for extension of reduced thin volume
Drop check which has prevented resize of reduce thin volume with
external origin. User is supposed to use 'zeroing' to get 'clean'
chunks.
2015-06-18 18:48:59 +02:00
Zdenek Kabelac
69132f55ea libdm: add dm_tree_node_set_thin_pool_read_only
Support thin-pool tree node with activation in read-only mode.
(Native kernel API).
2015-06-18 15:15:39 +02:00
David Teigland
fd1376ebef libdaemon: move compare_config to lib
so it can be used elsewhere.
2015-06-17 13:07:52 -05:00
Peter Rajnoha
0a203070f5 cleanup: missing target_type check in device_is_usable filter 2015-06-17 14:27:48 +02:00
Peter Rajnoha
5577f2f4f0 cleanup: || instead of |
More efficient with same result here.
2015-06-17 14:12:58 +02:00
Peter Rajnoha
1e6a926e85 filter: filter-usable: consider snapshot and origin LV as unusable if its component is suspended
Note that this is just a quick fix and it needs more robust fix to
encompass any combination, not just the (old) snapshot one!

This started with this report:
  https://bugzilla.redhat.com/show_bug.cgi?id=1219222

If we have devices/ignore_suspended_devices=1 set based on which we
filter out suspended devices as unusable (or if we ignore suspended
devices by force, e.g. during lvconvert called from dmeventd) and
when we have snapshot and snapshot origin devices in the play, we
need to look at their components unerneath (*-real and *-cow) to
check if they're not suspended. If they are, the snapshot/snapshot
origin is not usable as well and hence it needs to be filtered out
by filter-usable.c code which does suspended device filtering.

Not going into much details here, more details are in the bugzilla
mentioned above. However, this is a quick fix since snapshot
and this exact situation is not the only one. So this is
something that needs to be revisited and fixed properly
with full dm tree and checking the whole stack to state
whether the device at the very top is usable or not.
2015-06-17 13:37:53 +02:00
Peter Rajnoha
a9bc53d5f3 config: fix some settings incorrectly marked as CFG_DEFAULT_COMMENTED instead of CFG_DEFAULT_UNDEFINED and causing segfault
This patch fixes segfault which was caused by incorrectly marking some
settings CFG_DEFAULT_COMMENTED instead of CFG_DEFAULT_UNDEFINED - the
ones which have NULL default value, hence they're really undefined.
A regression caused by a98ceceb1d.

For example:

$ lvmconfig log/file
file="/a"

Before this patch:

$ lvmconfig --type diff
Segmentation fault (core dumped)

With this patch applied:

$ lvmconfig --type diff
log {
	file="/a"
}

The same applies for these settings:

  log/activate_file
  global/library_dir
  global/system_id_file
  <disk_area>/disk_area_id

There were also other settings with NULL default value and marked as
CFG_DEFAULT_COMMENTED instead of CFG_DEFAULT_UNDEFINED, but they were
cfg_array config settings where the NULL value was not causing segfault
(NULL == empty array).
2015-06-17 13:34:31 +02:00
David Teigland
da1f887060 Add a global get_cmd_name()
Which returns the string set by set_cmd_name().
2015-06-16 15:13:10 -05:00
David Teigland
e043e03cd8 lv_refresh: move the bulk of the function into lib
So that it can be used from other lib code.
2015-06-16 13:38:40 -05:00
David Teigland
3d9957e3dd man vgchange lvchange: mention activation option s
and improve the existing text about existing
activation options.
2015-06-16 13:28:07 -05:00
David Teigland
857296c823 man lvm: mention hyphens in option names 2015-06-16 10:33:01 -05:00
David Teigland
d5adec1056 Add the 's' activation mode
Just as 'e' means activation with an exclusive lock,
add an 's' to mean activation with a shared lock.

This allows the existing but implicit behavior of '-ay'
of clvm LVs to be specified explicitly.  For local VGs,
asy simply means ay, just like aey means ay.

For local VGs, ay == aey == asy

For clvm VGs,  ay == asy, aey == aey, asy == asy
2015-06-16 10:18:16 -05:00
David Teigland
1f318dbcee Ignore hyphens in long option names
The hyphens are removed from long option names before
being read.  This means that:

- Option name specifications in args.h must not include hyphens.
  (The hyphen in 'use-policies' is removed.)

- A user can include hyphens anywhere in the option name.
  All the following are equivalent:
  --vgmetadatacopies,
  --vg-metadata-copies,
  --v-g-m-e-t-a-d-a-t-a-c-o-p-i-e-s-
2015-06-16 09:35:52 -05:00
David Teigland
7fe5e4010c xlate: add new variants
New variants use the clearer function names from the kernel.
2015-06-16 09:30:14 -05:00
David Teigland
ce18fb61c0 lvmcache: mention lvconvert --cachemode
for changing the cache mode on an existing LV.
2015-06-15 14:30:58 -05:00
Zdenek Kabelac
e7eb5b0696 debug: better tracing messages
Enhance traced output.
2015-06-15 14:48:06 +02:00
Zdenek Kabelac
9a06ae7b35 libdm: better debug message
Print reason for failing ioctl if thin pool message fails.
2015-06-15 14:48:04 +02:00
Zdenek Kabelac
ac6b355978 cleanup: drop double const
Second const is unneeded.
Also always create whole array with MAX elements.
2015-06-15 14:46:44 +02:00
Zdenek Kabelac
edbdbddfb6 dmeventd: better debug
Avoid using 'static' variable within threaded environmnent for debuging.
2015-06-15 14:46:44 +02:00
Zdenek Kabelac
3d5f7f90c8 dmeventd: drop stack 2015-06-15 14:46:44 +02:00
Zdenek Kabelac
9da07f1d3e dmeventd: drop pthread_cancel
Drop unused pthread canceling as well as DEBUG printing in signal
handler.
2015-06-15 14:46:44 +02:00
Alasdair G Kergon
f715fefe31 post-release 2015-06-12 21:42:57 +01:00
Alasdair G Kergon
2c64762a40 pre-release 2015-06-12 21:40:56 +01:00
Petr Rockai
9c0049b1ce test: Ensure that outdated PVs are wiped just once. 2015-06-10 16:27:59 +02:00
Petr Rockai
632dde0cbc metadata: When outdated PVs are wiped, notify lvmetad about the fact. 2015-06-10 16:27:12 +02:00
Petr Rockai
c78b6f18d4 metadata: Reject lvmetad metadata extensions when reading from disk. 2015-06-10 16:25:57 +02:00
Petr Rockai
4f91ad64c3 lvmetad: Make it possible to clear the outdated PVs list for a VG. 2015-06-10 16:18:57 +02:00
Petr Rockai
756d027da5 metadata: Explain the pvs_outdated field in struct volume_group. 2015-06-10 16:17:45 +02:00
David Teigland
fd29c7f3a1 lvmetad, lvmpolld: remove DL_LIBS from Makefile
and rdynamic.  They are not needed.
2015-06-08 11:48:22 -05:00
Ondrej Kozina
7c31293221 lvmetad.c: internal err on modifying global handle with open connection
lvmetad_init() should not be called with open connection to the daemon.
Doing so is considered to be an internall error within lvm2 code.

Such coincidence can't occur within current code. Let's assure us it won't
ever happen.
2015-06-08 16:01:40 +02:00
Ondrej Kozina
b89ad7e2d4 lvmetad.h: rephrase API descriptions
Some of descritpions were misleading at least. Some were completely
off the reality.

lvmetad_init doesn't re-establish or initialise a connection
lvmetad_active and lvmetad_connect_or_warn can do so.
2015-06-08 16:01:32 +02:00
David Teigland
3225f8d175 man: lvmthin chunk and metadata sizes
Clear some stale information, and give a suggestion to use
a metadata size of 1GiB.
2015-05-27 15:53:01 -05:00
Zdenek Kabelac
778b66a719 tests: check for idle only for raid type 2015-05-27 11:59:10 +02:00
Zdenek Kabelac
6e4c04b1be lvmetad: missing wrapper for lvmetad less compilation 2015-05-27 11:44:33 +02:00
Zdenek Kabelac
d3abc25e76 tests: check for clmvd socket
A bit hacky since it expects PID_DIR == DEFAULT_RUN_DIR for now,
just to check whether it fixes startup clvmd sync problem.
2015-05-27 11:10:43 +02:00
Zdenek Kabelac
f0a4955eb1 tests: better check for array in sync
Update check for raid array being in sync - getting somewhat complex.
It's another way to fight with problems in:
https://bugzilla.redhat.com/show_bug.cgi?id=1210637
2015-05-27 11:10:43 +02:00
Zdenek Kabelac
c254743ef3 tests: drop debug print 2015-05-27 11:10:43 +02:00
Zdenek Kabelac
d1531ab26d cleanup: gcc warn fix, don't hide pvs() 2015-05-27 11:10:43 +02:00
Ondrej Kozina
1aba262edb lvmpolld: terminate error message with a dot and LF 2015-05-27 11:10:43 +02:00
Ondrej Kozina
f0268585dd WHATS_NEW: various updates
commit c069aff21b
commit 8af5f54824
2015-05-26 16:28:04 +02:00
Ondrej Kozina
8af5f54824 dmsetup: zero errno in before strtoul call
Testing errno value without explicitly setting to
zero in before the strtoul call may lead to
unexpected failures.
2015-05-26 16:27:10 +02:00
Ondrej Kozina
c069aff21b lvmpolld: zero errno in before strtoul call
Testing errno value without explicitly setting to
zero in before the strtoul call may lead to
unexpected failures.
2015-05-26 16:27:03 +02:00
Ondrej Kozina
a72a805896 lvconvert.c: fix whitespace mess 2015-05-26 16:26:57 +02:00
Alasdair G Kergon
eeb498627c libdm: Add dm_task_get_errno to return ioctl errno.
There are reports of unexplained ioctl failures when using dmeventd.
An explanation might be that the wrong value of errno is being used.

Change libdevmapper to store an errno set by from dm ioctl() directly
and provide it to the caller through a new dm_task_get_errno() function.

[Replaced f9510548667754d9209b232348ccd2d806c0f1d8]
2015-05-26 15:13:49 +01:00
Ondrej Kozina
b244fffc18 WHATS_NEW: update
update for commit: f8bf641095
2015-05-25 10:48:53 +02:00
Ondrej Kozina
da20e0c507 tests: add test for pvscan --cache --background
regression test for a segfault in pvscan --cache --background
bug fixed by commit:
f8bf641095
2015-05-25 10:48:45 +02:00
Ondrej Kozina
f8bf641095 lvmetad.c: ignore lvmetad global handle on disconnect
do not unset lvmetad global handle on disconnect. This is
hotfix for issue described in:
https://www.redhat.com/archives/linux-lvm/2015-May/msg00008.html

Reported-by: Christian Hesse <list@eworm.de>
2015-05-25 09:11:04 +02:00
Lidong Zhong
9d558fbcc2 lvconvert: change how to get failed mirrors number
Commit  b00711e312 improperly
convert _area_missing() replacment and moved check for
AREA_PV seg_type() into same if() section.

Signed-off-by: Lidong Zhong <lzhong@suse.com>
2015-05-22 15:35:36 +02:00
Peter Rajnoha
ba68aed836 scripts: activation generator: do not use --sysinit if lvmpolld used
If lvmetad is not used, we generate lvm2-activation{-early,-net}.service
systemd services to activate any VGs found on the system. So far we used
--sysinit during this activation as polling was still forked off of the
lvm activation command.

This has changed with lvmpolld - we have proper lvmpolld systemd
service now (activated via its socket unit). As such, we don't need
to use --sysinit anymore during activation in systemd environment
as polling was the only barrier to remove the need for --sysinit.
2015-05-21 12:20:30 +02:00
Ondrej Kozina
6d998aa13d lvmpolld-client.c: debug print when querying progress 2015-05-21 11:20:21 +02:00
Ondrej Kozina
01b06cb71b polldaemon.c: modify log levels in report_progress
There's a race when asking lvmpolld about progress_status and
actually reading the progress info from kernel:

Even with lvmpolld being used we read status info from
LVM2 command issued by a user (client side from lvmpolld perspective).
The whole cycle may look like following:

1) set up an operation that requires polling (i.e. pvmove /dev/sda)
2) notify lvmpolld about such operation (lvmpolld_poll_init())
3) in case 1) was not called with --background it would continue with:
4) Ask lvmpolld about progress status. it may respond with one of:
   a) in_progress
   b) not_found
   c) finished
   d) any low level error

5) provided the answer was 4a) try to read progress info from polling LV
(i.e. vg00/pvmove1). Repeat steps 4) and 5) until the answer is != 4a).

And now we got into racy configuration: lvmpolld answered with in_progress
but it may be the that in_between 4) and 5) the operation has already
finished and polling LV is already gone or there's nothing to ask for.
Up to now, 5) would report warning and it could print such warning many
times if --interval was set to 0.

We don't want to scary users by warnings in such situation so let's just
print these messages in verbose mode. Error messages due to error while
reading kernel status info (on existing, active and locked LV) remained
the same.
2015-05-21 11:20:11 +02:00
Petr Rockai
43224f22e4 format_text: Parse (optional) outdated_pvs section in VG metadata. 2015-05-20 19:46:14 +02:00
Petr Rockai
e8d00e0687 lvmetad: Set up lvmcache & PV structs for outdated_pvs. 2015-05-20 19:46:14 +02:00
Petr Rockai
55f3369692 lvmetad: Provide entire pvmeta sections for outdated_pvs. 2015-05-20 19:46:14 +02:00
Petr Rockai
611c8b6d29 metadata: Add pvs_outdated to struct volume_group.
This is a list of PVs that should have their MDAs wiped because they carry
outdated metadata (that used to belong to the VG they are attached to).
2015-05-20 19:46:14 +02:00
Petr Rockai
5435346052 metadata: Factor _wipe_outdated_pvs() PVs out of _vg_read(). 2015-05-20 19:46:13 +02:00
Petr Rockai
1562cd7320 lvmetad: Attach an outdated_pvs list to vg_lookup replies. 2015-05-20 19:46:13 +02:00
Petr Rockai
da1527d65d lvmetad: Clear the vgid_to_outdated_pvs hash on shutdown. 2015-05-20 19:46:13 +02:00
Petr Rockai
925268794f lvmetad: Maintain info about outdated PVs. 2015-05-20 19:46:13 +02:00
Zdenek Kabelac
f3c7bd4004 makefiles: use bash subshell
Avoid using  make's $(shell invocation since the eval order is
then somewhat different and use $$(  subshell.

This also fixes a problem when more then one symbol is found,
since target shell has been given separate word list
so the 'R' assignment would need "" around it.
2015-05-20 09:33:51 +02:00
Zdenek Kabelac
682e0c898e configure: fix missing [ 2015-05-20 09:32:03 +02:00
Ondrej Kozina
788e4c5423 WHATS_NEW: various updates 2015-05-19 21:01:24 +02:00
Ondrej Kozina
e6b5eb88f2 polldaemon.c: do not report error when LV not found
currently in wait_for_single_lv() fn trying to poll missing pvmove LV
is considered success. It may have been already finished by another
instance of polldaemon. either by another forked off polldaemon
or by lvmpolld.

Let's try to handle the mirror conversion and snapshot merge the same
way.
2015-05-19 20:56:46 +02:00
David Teigland
cf5b4a2286 lvconvert.c: drop get_vg_lock_and_logical_volume fn 2015-05-19 20:56:32 +02:00
David Teigland
f400f9db19 pvmove.c: code cleanup 2015-05-19 20:56:24 +02:00
David Teigland
7a8ce8dbf7 polldaemon: remove get_copy_vg and get_copy_lv wrappers
These wrappers have been replaced by direct calls
to vg_read() and find_lv() in previous commits.

This commit should have no functional impact since
all bits were already unreachable.
2015-05-19 20:56:15 +02:00
Ondrej Kozina
6fba37777c polldaemon.c: call find_lv directly 2015-05-19 20:56:07 +02:00
David Teigland
08114840ca lvconvert.c: call find_lv directly 2015-05-19 20:55:57 +02:00
David Teigland
0d300b70f9 polldaemon.c: call vg_read directly
replace calls in wait_for_single_lv() and report_progress() fns
2015-05-19 20:55:50 +02:00
David Teigland
15939e3435 lvconvert.c: call vg_read directly 2015-05-19 20:55:41 +02:00
David Teigland
131c657735 pvmove.c: call vg_read directly 2015-05-19 20:55:31 +02:00
Ondrej Kozina
e5e0e22022 polldaemon: move dev_close_all out of poll_get_copy_vg
let's call dev_close_all() only before we're about to 'sleep'
for at least one second during the polling.

(it's questionable whether to call dev_close_all() at all in
polldaemon code. Natural extension would be to drop it completely)
2015-05-19 20:55:22 +02:00
David Teigland
e27182249a tests: add test for duplicate pvs 2015-05-19 11:02:53 -05:00
Zdenek Kabelac
dc49e1cde0 configure: update localedir
Previous patch incorrectly skipped replace of @LOCALEDIR@.

The standard option is --localedir  so use --with-localedir
as backward compatible option and set localedir if it's not
yet been set (if the could ever happen).

Use double-eval to translate $datarootdir to $prefix to real dir.
2015-05-18 18:48:18 +02:00
Zdenek Kabelac
aa2d39c2ca configure: LOCALEDIR needs evaluated value
Also fix typo.
2015-05-18 13:06:34 +02:00
Zdenek Kabelac
0cb9df3cec tests: fix calcucaltion
Code works properly.
2015-05-18 12:45:43 +02:00
Zdenek Kabelac
caaca15854 tests: thin_restore not needed
Few more test which could live without thin_restore.
2015-05-18 12:45:42 +02:00
Zdenek Kabelac
62ac80c8fa makefiles: drop LVM_SHARED_PATH
We already have LVM_PATH define used everywhere else
to access LVM binary so stay with one name.
2015-05-18 12:45:42 +02:00
Zdenek Kabelac
30c3bbcd9e makefiles: better clean
More exact clean of library exported symbols files.

Also use $(firstword) test to check for empty string
so 'make clean' has now cleaner condensed look.

Clean also created include links.
2015-05-18 12:45:42 +02:00
Zdenek Kabelac
1bed578535 makefiles: use := for shell calls 2015-05-18 12:45:42 +02:00
Zdenek Kabelac
bf2b1986c2 makefiles: use single target
Possibly  easier to follow - to have just a single dependency line
and use  if() within rule.

Also replace $(words) with $(firstword) which is more commonly used.
2015-05-18 12:45:42 +02:00
Zdenek Kabelac
fe00b163d6 configure: move DEFS to configure.h 2015-05-18 12:43:25 +02:00
Zdenek Kabelac
76cc477fba tests: no warn if test does not need thin_repair
Set LVM_TEST_THIN_REPAIR_CMD to /bin/false for test which
doesn't need it.

This way - even if on the system there is no such tool present,
test will not result with warning about missing tool.

Also remove from Makefile settings of TEST vars which are set in
through /lib/paths  - this also allows to override them in test.
2015-05-17 20:24:36 +02:00
Alasdair G Kergon
2fca6cdeb3 post-release 2015-05-15 23:28:47 +01:00
274 changed files with 29828 additions and 2948 deletions

11
.gitignore vendored
View File

@@ -1,13 +1,16 @@
*.5
*.7
*.8
*.a
*.d
*.o
*.orig
*.pc
*.pot
*.rej
*.so
*.so.*
*.swp
*.sw*
*~
.export.sym
@@ -17,11 +20,11 @@
Makefile
make.tmpl
configure.h
version.h
/autom4te.cache/
/autoscan.log
/config.log
/config.status
/configure.scan
/cscope.out
/tags
/tmp/

View File

@@ -95,7 +95,7 @@ endif
DISTCLEAN_TARGETS += cscope.out
CLEAN_DIRS += autom4te.cache
check check_system check_cluster check_local check_lvmetad unit: all
check check_system check_cluster check_local check_lvmetad check_lvmpolld unit: all
$(MAKE) -C test $(@)
conf.generate: tools
@@ -223,3 +223,13 @@ memcheck: test-programs
ruby-test:
$(RUBY) report-generators/test/ts.rb
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 '{}' +
DISTCLEAN_TARGETS += tags
endif

View File

@@ -1 +1 @@
2.02.120(2)-git (2015-05-15)
2.02.127(2)-git (2015-07-24)

View File

@@ -1 +1 @@
1.02.97-git (2015-05-15)
1.02.104-git (2015-07-24)

View File

@@ -1,3 +1,81 @@
Version 2.02.127 -
=================================
Do not init filters, locking, lvmetad, lvmpolld if command doesn't use it.
Recognise vg/lv name format in dmsetup.
Fix regression in cache causing some PVs to bypass filters (2.02.105).
Version 2.02.126 - 24th July 2015
=================================
Fix long option hyphen removal. (2.02.122)
Fix clvmd freeze if client disappears without first releasing its locks.
Fix lvconvert segfaults while performing snapshots merge.
Ignore errors during detection if use_blkid_wiping=1 and --force is used.
Recognise DM_ABORT_ON_INTERNAL_ERRORS env var override in lvm logging fn.
Fix alloc segfault when extending LV with fewer stripes than in first seg.
Fix handling of cache policy name.
Set cache policy before with the first lvm2 cache pool metadata commit.
Fix detection of thin-pool overprovisioning (2.02.124).
Fix lvmpolld segfaults on 32 bit architectures.
Add lvmlockd lock_args validation to vg_validate.
Fix ignored --startstopservices option if running lvmconf with systemd.
Hide sanlock LVs when processing LVs in VG unless named or --all used.
Version 2.02.125 - 7th July 2015
================================
Fix getline memory usage in lvmpolld.
Add support --clear-needs-check-flag for cache_check of cache pool metadata.
Add lvmetactl for developer use only.
Rename global/lock_retries to lvmlockd_retries.
Replace --enable-lvmlockd by --enable-lockd-sanlock and --enable-lockd-dlm.
Version 2.02.124 - 3rd July 2015
================================
Move sending thin pool messages from resume to suspend phase.
Report warning when pool is overprovisioned and not auto resized.
Recognize free-form date/time values for lv_time field in selection criteria.
Added experimental lvmlockd with configure --enable-lvmlockd.
Fix regression in select to match string fields if using synonyms (2.02.123).
Fix regression when printing more lv names via display_lvname (2.02.122).
Add missing error logging to unlock_vg and sync_local_dev_names callers.
Version 2.02.123 - 30th June 2015
=================================
Add report/time_format lvm.conf option to define time format for report.
Fix makefile shell compare == when building lvmetad lvmpolld (2.02.120).
Add --type full to lvmconfig for full configuration tree view.
Add undocumented environment variables to lvm man page. (2.02.119)
Add device synchronization point before activating a new snapshot.
Add --withspaces to lvmconfig to add spaces in output for better readability.
Add custom main function to libdaemon.
Use lvmetad to track out-of-date metadata discovered.
Version 2.02.122 - 20th June 2015
=================================
Flush stdout before printing to stderr.
Use pre-allocated buffer for printed LV names in display_lvname.
Support thins with size of external origin unaligned with thin pool chunk.
Allow extension of reduced thin volumes with external origins.
Consider snapshot and origin LV as unusable if component devices suspended.
Fix lvmconfig segfault on settings with undefined default value (2.02.120).
Add explicit 's' (shared) LV activation mode.
Ignore hyphens in long options names (i.e. --long-option == --longoption).
Version 2.02.121 - 12th June 2015
=================================
Distinguish between on-disk and lvmetad versions of text metadata.
Remove DL_LIBS from Makefiles for daemons that don't need them.
Zero errno in before strtoul call in dmsetup if tested after the call.
Zero errno in before strtoul call in lvmpolld.
Fix a segfault in pvscan --cache --background command.
Fix test for AREA_PV when checking for failed mirrors.
Do not use --sysinit in lvm2-activation{-early,-net}.service if lvmpolld used.
Maintain outdated PV info in lvmetad till all old metadata is gone from disk.
Do not fail polling when poll LV not found (already finished or removed).
Replace poll_get_copy_vg/lv fns with vg_read() and find_lv() in polldaemon.
Close all device fds only in before sleep call in polldaemon.
Simplify Makefile targets that generate exported symbols.
Move various -D settings from Makefiles to configure.h.
Version 2.02.120 - 15th May 2015
================================
Make various adjustments to Makefile compilation flags.

View File

@@ -1,3 +1,63 @@
Version 1.02.104 -
=================================
Add dmstats.8 man page
Add report stats sub-command to provide repeating stats reports.
Add clear, delete, list, and print stats sub-commands.
Add create stats sub-command and --start, --length, --areas and --areasize.
Add a 'stats' command to dmsetup to configure, manage and report stats data.
Add --regionid, --allregions to specify a single stats region or all regions.
Add --allprograms for stats commands that filter by program ID.
Add --auxdata and --programid arguments to set stats aux data and program ID.
Add statistics fields to -o <field>
Add libdm-stats library to allow management of device-mapper statistics.
Add --units to control report field output units.
Add support to redisplay column headings for repeating column reports.
Fix report header and row resource leaks.
Report timestamps of ioctls with dmsetup -vvv.
Recognize report field name variants without any underscores too.
Add dmsetup --interval and --count to repeat reports at specified intervals.
Add dm_timestamp functions to libdevmapper.
Version 1.02.103 - 24th July 2015
=================================
Introduce libdevmapper wrappers for all malloc-related functions.
Version 1.02.102 - 7th July 2015
================================
Include tool.h for default non-library use.
Introduce format macros with embedded % such as FMTu64.
Version 1.02.101 - 3rd July 2015
================================
Add experimental support to passing messages in suspend tree.
Add dm_report_value_cache_{set,get} to support caching during report/select.
Add dm_report_reserved_handler to handle report reserved value actions.
Support dynamic value in select: DM_REPORT_FIELD_RESERVED_VALUE_DYNAMIC_VALUE.
Support fuzzy names in select: DM_REPORT_FIELD_RESERVED_VALUE_FUZZY_NAMES.
Thin pool trace messages show a device name and major:minor.
Version 1.02.100 - 30th June 2015
=================================
Add since, after, until and before time operators to be used in selection.
Add support for time in reports and selection: DM_REPORT_FIELD_TYPE_TIME.
Support report reserved value ranges: DM_REPORT_FIELD_RESERVED_VALUE_RANGE.
Support report reserved value names: DM_REPORT_FIELD_RESERVED_VALUE_NAMED.
Add DM_CONFIG_VALUE_FMT_{INT_OCTAL,STRING_NO_QUOTES} config value format flag.
Add DM_CONFIG_VALUE_FMT_COMMON_{ARRAY,EXTRA_SPACE} config value format flag.
Add dm_config_value_{get,set}_format_flags to get and set config value format.
Version 1.02.99 - 20th June 2015
================================
New dm_tree_node_set_thin_pool_read_only(DM_1_02_99) for read-only thin pool.
Enhance error message when thin-pool message fails.
Fix dmeventd logging to avoid threaded use of static variable.
Remove redundant dmeventd SIGALRM coded.
Version 1.02.98 - 12th June 2015
================================
Add dm_task_get_errno() to return any unexpected errno from a dm ioctl call.
Use copy of errno made after each dm ioctl call in case errno changes later.
Version 1.02.97 - 15th May 2015
===============================
New dm_task_get_info(DM_1_02_97) supports internal_suspend state.

4
aclocal.m4 vendored
View File

@@ -1,6 +1,6 @@
# generated automatically by aclocal 1.14.1 -*- Autoconf -*-
# generated automatically by aclocal 1.15 -*- Autoconf -*-
# Copyright (C) 1996-2013 Free Software Foundation, Inc.
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,

4
conf/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
command_profile_template.profile
example.conf
lvmlocal.conf
metadata_profile_template.profile

View File

@@ -27,8 +27,8 @@ include $(top_builddir)/make.tmpl
.PHONY: install_conf install_localconf install_profiles
generate:
(cat $(top_srcdir)/conf/example.conf.base && LD_LIBRARY_PATH=$(top_builddir)/libdm:$(LD_LIBRARY_PATH) $(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withcomments --ignorelocal) > example.conf.in
(cat $(top_srcdir)/conf/lvmlocal.conf.base && LD_LIBRARY_PATH=$(top_builddir)/libdm:$(LD_LIBRARY_PATH) $(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withcomments local) > lvmlocal.conf.in
(cat $(top_srcdir)/conf/example.conf.base && LD_LIBRARY_PATH=$(top_builddir)/libdm:$(LD_LIBRARY_PATH) $(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withcomments --ignorelocal --withspaces) > example.conf.in
(cat $(top_srcdir)/conf/lvmlocal.conf.base && LD_LIBRARY_PATH=$(top_builddir)/libdm:$(LD_LIBRARY_PATH) $(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withcomments --withspaces local) > lvmlocal.conf.in
install_conf: $(CONFSRC)
@if [ ! -e $(confdir)/$(CONFDEST) ]; then \

View File

@@ -4,6 +4,17 @@
#
# Refer to 'man lvm.conf' for further information including the file layout.
#
# Refer to 'man lvm.conf' for information about how settings configured in
# this file are combined with built-in values and command line options to
# arrive at the final values used by LVM.
#
# Refer to 'man lvmconfig' for information about displaying the built-in
# and configured values used by LVM.
#
# If a default value is set in this file (not commented out), then a
# new version of LVM using this file will continue using that value,
# even if the new version of LVM changes the built-in default value.
#
# To put this file in a different directory and override @DEFAULT_SYS_DIR@ set
# the environment variable LVM_SYSTEM_DIR before running the tools.
#
@@ -92,7 +103,6 @@ devices {
# Example:
# preferred_names = [ "^/dev/mpath/", "^/dev/mapper/mpath", "^/dev/[hs]d" ]
# This configuration option does not have a default value defined.
# preferred_names=[]
# Configuration option devices/filter.
# Limit the block devices that are used by LVM commands.
@@ -128,8 +138,7 @@ devices {
# Example:
# Use anchors to be very specific.
# filter = [ "a|^/dev/hda8$|", "r|.*/|" ]
# This configuration option does not have a default value defined.
# filter = []
# filter = [ "a|.*/|" ]
# Configuration option devices/global_filter.
# Limit the block devices that are used by LVM system components.
@@ -138,8 +147,7 @@ devices {
# and lvmetad. Use global_filter to hide devices from these LVM
# system components. The syntax is the same as devices/filter.
# Devices rejected by global_filter are not opened by LVM.
# This configuration option does not have a default value defined.
# global_filter = []
# global_filter = [ "a|.*/|" ]
# Configuration option devices/cache_dir.
# Directory in which to store the device cache file.
@@ -167,7 +175,6 @@ devices {
# types = [ "fd", 16 ]
# This configuration option is advanced.
# This configuration option does not have a default value defined.
# types = []
# Configuration option devices/sysfs_scan.
# Restrict device scanning to block devices appearing in sysfs.
@@ -316,7 +323,6 @@ allocation {
# they are situated.
# cling_tag_list = [ "@site1", "@site2" ]
# This configuration option does not have a default value defined.
# cling_tag_list = []
# Configuration option allocation/maximise_cling.
# Use a previous allocation algorithm.
@@ -336,7 +342,7 @@ allocation {
# MD device signatures, swap signature, and LUKS signatures.
# To see the list of signatures recognized by blkid, check the
# output of the 'blkid -k' command.
use_blkid_wiping = 1
use_blkid_wiping = @DEFAULT_USE_BLKID_WIPING@
# Configuration option allocation/wipe_signatures_when_zeroing_new_lvs.
# Look for and erase any signatures while zeroing a new LV.
@@ -389,7 +395,6 @@ allocation {
# end of the spectrum. Supported values range from 32(kiB) to
# 1048576 in multiples of 32.
# This configuration option does not have a default value defined.
# cache_pool_chunk_size = 128
# Configuration option allocation/thin_pool_metadata_require_separate_pvs.
# Thin pool metdata and data will always use different PVs.
@@ -427,7 +432,6 @@ allocation {
# chunk size starting from 64KB. Supported values are in
# the range 64 to 1048576.
# This configuration option does not have a default value defined.
# thin_pool_chunk_size = 128
# Configuration option allocation/physical_extent_size.
# Default physical extent size to use for new VGs (in KB).
@@ -461,7 +465,6 @@ log {
# Configuration option log/file.
# Write error and debug log messages to a file specified here.
# This configuration option does not have a default value defined.
# file = ""
# Configuration option log/overwrite.
# Overwrite the log file each time the program is run.
@@ -492,7 +495,7 @@ log {
# Configuration option log/activation.
# Log messages during activation.
# Don't use this in low memory situations (can deadlock).
# activation = 0
activation = 0
# Configuration option log/debug_classes.
# Select log messages by class.
@@ -502,8 +505,7 @@ log {
# memory, devices, activation, allocation,
# lvmetad, metadata, cache, locking, lvmpolld.
# Use "all" to see everything.
debug_classes = ["memory", "devices", "activation", "allocation",
"lvmetad", "metadata", "cache", "locking", "lvmpolld"]
debug_classes = [ "memory", "devices", "activation", "allocation", "lvmetad", "metadata", "cache", "locking", "lvmpolld" ]
}
# Configuration section backup.
@@ -600,7 +602,7 @@ global {
# The LVM1 tools need to be installed with .lvm1 suffices,
# e.g. vgscan.lvm1. They will stop working once the lvm2
# on-disk metadata format is used.
# fallback_to_lvm1 = 0
# fallback_to_lvm1 = @DEFAULT_FALLBACK_TO_LVM1@
# Configuration option global/format.
# The default metadata format that commands should use.
@@ -613,11 +615,9 @@ global {
# If support for LVM1 metadata was compiled as a shared library use
# format_libraries = "liblvm2format1.so"
# This configuration option does not have a default value defined.
# format_libraries = []
# Configuration option global/segment_libraries.
# This configuration option does not have a default value defined.
# segment_libraries = []
# Configuration option global/proc.
# Location of proc filesystem.
@@ -694,7 +694,6 @@ global {
# Configuration option global/library_dir.
# Search this directory first for shared libraries.
# This configuration option does not have a default value defined.
# library_dir = ""
# Configuration option global/locking_library.
# The external locking library to use for locking_type 2.
@@ -822,6 +821,23 @@ global {
# is seen.
use_lvmetad = @DEFAULT_USE_LVMETAD@
# Configuration option global/use_lvmlockd.
# Use lvmlockd for locking among hosts using LVM on shared storage.
use_lvmlockd = 0
# Configuration option global/lvmlockd_lock_retries.
# Retry lvmlockd lock requests this many times.
# lvmlockd_lock_retries = 3
# Configuration option global/sanlock_lv_extend.
# Size in MiB to extend the internal LV holding sanlock locks.
# The internal LV holds locks for each LV in the VG, and after
# enough LVs have been created, the internal LV needs to be extended.
# lvcreate will automatically extend the internal LV when needed by
# the amount specified here. Setting this to 0 disables the
# automatic extension and can cause lvcreate to fail.
# sanlock_lv_extend = 256
# Configuration option global/thin_check_executable.
# The full path to the thin_check command.
# LVM uses this command to check that a thin metadata
@@ -856,12 +872,11 @@ global {
# ignorable errors and fix them later.
# With thin_check version 3.2 or newer you should add
# --clear-needs-check-flag.
# thin_check_options = ["-q", "--clear-needs-check-flag"]
# thin_check_options = [ "-q", "--clear-needs-check-flag" ]
# Configuration option global/thin_repair_options.
# List of options passed to the thin_repair command.
# This configuration option does not have a default value defined.
# thin_repair_options = ""
# thin_repair_options = [ "" ]
# Configuration option global/thin_disabled_features.
# Features to not use in the thin driver.
@@ -873,7 +888,6 @@ global {
# Example:
# thin_disabled_features = [ "discards", "block_size" ]
# This configuration option does not have a default value defined.
# thin_disabled_features = []
# Configuration option global/cache_check_executable.
# The full path to the cache_check command.
@@ -886,6 +900,8 @@ global {
# Also see cache_check_options.
# The cache tools are available from the package
# device-mapper-persistent-data.
# With cache_check version 5.0 or newer you should add
# --clear-needs-check-flag.
# cache_check_executable = "@CACHE_CHECK_CMD@"
# Configuration option global/cache_dump_executable.
@@ -904,12 +920,11 @@ global {
# Configuration option global/cache_check_options.
# List of options passed to the cache_check command.
# cache_check_options = "-q"
# cache_check_options = [ "-q", "--clear-needs-check-flag" ]
# Configuration option global/cache_repair_options.
# List of options passed to the cache_repair command.
# This configuration option does not have a default value defined.
# cache_repair_options = ""
# cache_repair_options = [ "" ]
# Configuration option global/system_id_source.
# The method LVM uses to set the local system ID.
@@ -925,29 +940,29 @@ global {
# 'local' section of an lvm configuration file, e.g. lvmlocal.conf.
# uname - Set the system ID from the hostname (uname) of the system.
# System IDs beginning localhost are not permitted.
# machineid - Use the contents of the file @CONFDIR@/machine-id to set the
# machineid - Use the contents of the machine-id file to set the
# system ID. Some systems create this file at installation time.
# See 'man machine-id'.
# See 'man machine-id' and global/etc.
# file - Use the contents of another file (system_id_file) to set
# the system ID.
# system_id_source = "none"
system_id_source = "none"
# Configuration option global/system_id_file.
# The full path to the file containing a system ID.
# This is used when system_id_source is set to 'file'.
# Comments starting with the character # are ignored.
# This configuration option does not have a default value defined.
# system_id_file = ""
# Configuration option global/use_lvmpolld.
# Use lvmpolld to supervise long running LVM commands.
# When enabled, control of long running LVM commands is transferred
# from the original LVM command to the lvmpolld daemon. This allows
# from the original LVM command to the lvmpolld daemon. This allows
# the operation to continue independent of the original LVM command.
# After lvmpolld takes over, the LVM command displays the progress
# of the ongoing operation. lvmpolld itself runs LVM commands to manage
# the progress of ongoing operations. lvmpolld can be used as a native
# of the ongoing operation. lvmpolld itself runs LVM commands to manage
# the progress of ongoing operations. lvmpolld can be used as a native
# systemd service, which allows it to be started on demand, and to use
# its own control group. When this option is disabled, LVM commands will
# its own control group. When this option is disabled, LVM commands will
# supervise long running operations by forking themselves.
use_lvmpolld = @DEFAULT_USE_LVMPOLLD@
}
@@ -1048,7 +1063,6 @@ activation {
# Example:
# volume_list = [ "vg1", "vg2/lvol1", "@tag1", "@*" ]
# This configuration option does not have a default value defined.
# volume_list = []
# Configuration option activation/auto_activation_volume_list.
# Only LVs selected by this list are auto-activated.
@@ -1080,7 +1094,6 @@ activation {
# Possible options are: vgname, vgname/lvname, @tag, @*
# See volume_list for how these options are matched to LVs.
# This configuration option does not have a default value defined.
# auto_activation_volume_list = []
# Configuration option activation/read_only_volume_list.
# LVs in this list are activated in read-only mode.
@@ -1092,7 +1105,6 @@ activation {
# Possible options are: vgname, vgname/lvname, @tag, @*
# See volume_list for how these options are matched to LVs.
# This configuration option does not have a default value defined.
# read_only_volume_list = []
# Configuration option activation/raid_region_size.
# Size in KiB of each raid or mirror synchronization region.
@@ -1221,7 +1233,7 @@ activation {
# Auto-extending a thin pool adds this percent extra space.
# The amount of additional space added to a thin pool is this
# percent of its current size.
thin_pool_autoextend_percent=20
thin_pool_autoextend_percent = 20
# Configuration option activation/mlock_filter.
# Do not mlock these memory areas.
@@ -1240,7 +1252,6 @@ activation {
# mlock_filter = [ "locale/locale-archive", "gconv/gconv-modules.cache" ]
# This configuration option is advanced.
# This configuration option does not have a default value defined.
# mlock_filter = []
# Configuration option activation/use_mlockall.
# Use the old behavior of mlockall to pin all memory.
@@ -1294,6 +1305,16 @@ activation {
# sometimes assist with data recovery.
# The '--activationmode' option overrides this setting.
activation_mode = "degraded"
# Configuration option activation/lock_start_list.
# Locking is started only for VGs selected by this list.
# The rules are the same as those for LVs in volume_list.
# This configuration option does not have a default value defined.
# Configuration option activation/auto_lock_start_list.
# Locking is auto-started only for VGs selected by this list.
# The rules are the same as those for LVs in auto_activation_volume_list.
# This configuration option does not have a default value defined.
}
# Configuration section metadata.
@@ -1361,7 +1382,6 @@ activation {
# dirs = [ "/etc/lvm/metadata", "/mnt/disk2/lvm/metadata2" ]
# This configuration option is advanced.
# This configuration option does not have a default value defined.
# dirs = []
# }
# Configuration section report.
@@ -1410,7 +1430,7 @@ activation {
# Configuration option report/colums_as_rows.
# Output each column as a row.
# If set, this also implies report/prefixes = 1.
# If set, this also implies report/prefixes=1.
# colums_as_rows = 0
# Configuration option report/binary_values_as_numeric.
@@ -1420,6 +1440,80 @@ activation {
# value could not be determined).
# binary_values_as_numeric = 0
# Configuration option report/time_format.
# Set time format for fields reporting time values.
# Format specification is a string which may contain special character
# sequences and ordinary character sequences. Ordinary character sequences
# are copied verbatim. Each special character sequence is introduced by '%'
# character and such sequence is then substituted with a value as described below:
# %a The abbreviated name of the day of the week according to the
# current locale.
# %A The full name of the day of the week according to the current locale.
# %b The abbreviated month name according to the current locale.
# %B The full month name according to the current locale.
# %c The preferred date and time representation for the current locale. (alt E)
# %C The century number (year/100) as a 2-digit integer. (alt E)
# %d The day of the month as a decimal number (range 01 to 31). (alt O)
# %D Equivalent to %m/%d/%y. (For Americans only. Americans should
# note that in other countries%d/%m/%y is rather common. This means
# that in international context this format is ambiguous and should not
# be used.
# %e Like %d, the day of the month as a decimal number, but a leading zero
# is replaced by a space. (alt O)
# %E Modifier: use alternative local-dependent representation if available.
# %F Equivalent to %Y-%m-%d (the ISO 8601 date format).
# %G The ISO 8601 week-based year with century as adecimal number. The 4-digit
# year corresponding to the ISO week number (see %V). This has the same
# format and value as %Y, except that if the ISO week number belongs to
# the previous or next year, that year is used instead.
# %g Like %G, but without century, that is, with a 2-digit year (00-99).
# %h Equivalent to %b.
# %H The hour as a decimal number using a 24-hour clock (range 00 to 23). (alt O)
# %I The hour as a decimal number using a 12-hour clock (range 01 to 12). (alt O)
# %j The day of the year as a decimal number (range 001 to 366).
# %k The hour (24-hour clock) as a decimal number (range 0 to 23);
# single digits are preceded by a blank. (See also %H.)
# %l The hour (12-hour clock) as a decimal number (range 1 to 12);
# single digits are preceded by a blank. (See also %I.)
# %m The month as a decimal number (range 01 to 12). (alt O)
# %M The minute as a decimal number (range 00 to 59). (alt O)
# %O Modifier: use alternative numeric symbols.
# %p Either "AM" or "PM" according to the given time value,
# or the corresponding strings for the current locale. Noon is
# treated as "PM" and midnight as "AM".
# %P Like %p but in lowercase: "am" or "pm" or a corresponding
# string for the current locale.
# %r The time in a.m. or p.m. notation. In the POSIX locale this is
# equivalent to %I:%M:%S %p.
# %R The time in 24-hour notation (%H:%M). For a version including
# the seconds, see %T below.
# %s The number of seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC)
# %S The second as a decimal number (range 00 to 60).
# (The range is up to 60 to allow for occasional leap seconds.) (alt O)
# %t A tab character.
# %T The time in 24-hour notation (%H:%M:%S).
# %u The day of the week as a decimal, range 1 to 7, Monday being 1.
# See also %w. (alt O)
# %U The week number of the current year as a decimal number,
# range 00 to 53, starting with the first Sunday as the first
# day of week 01. See also %V and %W. (alt O)
# %V The ISO 8601 week number of the current year as a decimal number,
# range 01 to 53, where week 1 is the first week that has at least 4 days
# in the new year. See also %U and %W. (alt O)
# %w The day of the week as a decimal, range 0 to 6, Sunday being 0.
# See also %u. (alt O)
# %W The week number of the current year as a decimal number, range 00 to 53,
# starting with the first Monday as the first day of week 01. (alt O)
# %x The preferred date representation for the current locale without the time. (alt E)
# %X The preferred time representation for the current locale without the date. (alt E)
# %y The year as a decimal number without a century (range 00 to 99). (alt E, alt O)
# %Y The year as a decimal number including the century. (alt E)
# %z The +hhmm or -hhmm numeric timezone (that is, the hour and minute
# offset from UTC).
# %Z The timezone name or abbreviation.
# %% A literal '%' character.
# time_format = "%Y-%m-%d %T %z"
# Configuration option report/devtypes_sort.
# List of columns to sort by when reporting 'lvm devtypes' command.
# See 'lvm devtypes -o help' for the list of possible fields.
@@ -1572,7 +1666,6 @@ dmeventd {
# bar is given to the hosts named machine1 and machine2.
# tags { foo { } bar { host_list = [ "machine1", "machine2" ] } }
# This configuration section has variable name.
# This configuration section does not have a default value defined.
# tag {
# Configuration option tags/<tag>/host_list.
@@ -1582,6 +1675,5 @@ dmeventd {
# matches an entry in this list, the name of the
# subsection is applied to the machine as a 'host tag'.
# This configuration option does not have a default value defined.
# host_list = ""
# }
# }

View File

@@ -36,8 +36,7 @@ local {
# Example:
# Set the system_id to the string 'host1'.
# system_id = "host1"
# This configuration option does not have a default value defined.
# system_id=""
# system_id = ""
# Configuration option local/extra_system_ids.
# A list of extra VG system IDs the local host can access.
@@ -49,5 +48,10 @@ local {
# Use this only after consulting 'man lvmsystemid'
# to be certain of correct usage and possible dangers.
# This configuration option does not have a default value defined.
# extra_system_ids=[]
# Configuration option local/host_id.
# The lvmlockd sanlock host_id.
# This must be a unique among all hosts,
# and must be between 1 and 2000.
# host_id = 0
}

1245
configure vendored

File diff suppressed because it is too large Load Diff

View File

@@ -39,6 +39,9 @@ case "$host_os" in
DEVMAPPER=yes
LVMETAD=no
LVMPOLLD=no
LVMLOCKD=no
LOCKDSANLOCK=no
LOCKDDLM=no
ODIRECT=yes
DM_IOCTLS=yes
SELINUX=yes
@@ -88,14 +91,19 @@ AC_PATH_TOOL(CSCOPE_CMD, cscope)
dnl -- Check for header files.
AC_HEADER_DIRENT
AC_HEADER_MAJOR
AC_HEADER_STDBOOL
AC_HEADER_STDC
AC_HEADER_SYS_WAIT
AC_HEADER_TIME
AC_CHECK_HEADERS([locale.h stddef.h syslog.h sys/file.h sys/time.h assert.h \
langinfo.h libgen.h signal.h sys/mman.h sys/resource.h sys/utsname.h \
sys/wait.h time.h], ,
[AC_MSG_ERROR(bailing out)])
AC_CHECK_HEADERS([assert.h ctype.h dirent.h errno.h fcntl.h float.h \
getopt.h inttypes.h langinfo.h libgen.h limits.h locale.h paths.h \
signal.h stdarg.h stddef.h stdio.h stdlib.h string.h sys/file.h \
sys/ioctl.h syslog.h sys/mman.h sys/param.h sys/resource.h sys/stat.h \
sys/time.h sys/types.h sys/utsname.h sys/wait.h time.h \
unistd.h], , [AC_MSG_ERROR(bailing out)])
AC_CHECK_HEADERS(termios.h sys/statvfs.h)
case "$host_os" in
linux*)
@@ -104,16 +112,13 @@ case "$host_os" in
AC_CHECK_HEADERS(machine/endian.h sys/disk.h,,AC_MSG_ERROR(bailing out)) ;;
esac
AC_CHECK_HEADERS([ctype.h dirent.h errno.h fcntl.h getopt.h inttypes.h limits.h \
stdarg.h stdio.h stdlib.h string.h sys/ioctl.h sys/param.h sys/stat.h \
sys/types.h unistd.h], , [AC_MSG_ERROR(bailing out)])
AC_CHECK_HEADERS(termios.h sys/statvfs.h)
################################################################################
dnl -- Check for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_C_INLINE
AC_CHECK_MEMBERS([struct stat.st_rdev])
AC_CHECK_TYPES([ptrdiff_t])
AC_STRUCT_TM
AC_TYPE_OFF_T
AC_TYPE_PID_T
AC_TYPE_SIGNAL
@@ -129,15 +134,13 @@ AC_TYPE_UINT8_T
AC_TYPE_UINT16_T
AC_TYPE_UINT32_T
AC_TYPE_UINT64_T
AC_CHECK_MEMBERS([struct stat.st_rdev])
AC_STRUCT_TM
################################################################################
dnl -- Check for functions
AC_CHECK_FUNCS([ftruncate gethostname getpagesize \
gettimeofday memset mkdir mkfifo rmdir munmap nl_langinfo setenv setlocale \
strcasecmp strchr strcspn strspn strdup strncasecmp strerror strrchr \
strstr strtol strtoul uname], , [AC_MSG_ERROR(bailing out)])
AC_CHECK_FUNCS([ftruncate gethostname getpagesize gettimeofday localtime_r \
memchr memset mkdir mkfifo munmap nl_langinfo realpath rmdir setenv \
setlocale strcasecmp strchr strcspn strdup strerror strncasecmp strndup \
strrchr strspn strstr strtol strtoul uname], , [AC_MSG_ERROR(bailing out)])
AC_FUNC_ALLOCA
AC_FUNC_CLOSEDIR_VOID
AC_FUNC_CHOWN
@@ -145,6 +148,7 @@ AC_FUNC_FORK
AC_FUNC_LSTAT
AC_FUNC_MALLOC
AC_FUNC_MEMCMP
AC_FUNC_MKTIME
AC_FUNC_MMAP
AC_FUNC_REALLOC
AC_FUNC_STAT
@@ -171,6 +175,9 @@ AC_SUBST(HAVE_FULL_RELRO)
################################################################################
dnl -- Prefix is /usr by default, the exec_prefix default is setup later
AC_PREFIX_DEFAULT(/usr)
if test "$prefix" = NONE; then
datarootdir=${ac_default_prefix}/share
fi
################################################################################
dnl -- Setup the ownership of the files
@@ -201,6 +208,7 @@ AC_ARG_WITH(device-uid,
[set the owner used for new device nodes [UID=0]]),
DM_DEVICE_UID=$withval, DM_DEVICE_UID=0)
AC_MSG_RESULT($DM_DEVICE_UID)
AC_DEFINE_UNQUOTED([DM_DEVICE_UID], [$DM_DEVICE_UID], [Define default owner for device node])
################################################################################
dnl -- Setup device group ownership
@@ -211,6 +219,7 @@ AC_ARG_WITH(device-gid,
[set the group used for new device nodes [GID=0]]),
DM_DEVICE_GID=$withval, DM_DEVICE_GID=0)
AC_MSG_RESULT($DM_DEVICE_GID)
AC_DEFINE_UNQUOTED([DM_DEVICE_GID], [$DM_DEVICE_GID], [Define default group for device node])
################################################################################
dnl -- Setup device mode
@@ -221,6 +230,7 @@ AC_ARG_WITH(device-mode,
[set the mode used for new device nodes [MODE=0600]]),
DM_DEVICE_MODE=$withval, DM_DEVICE_MODE=0600)
AC_MSG_RESULT($DM_DEVICE_MODE)
AC_DEFINE_UNQUOTED([DM_DEVICE_MODE], [$DM_DEVICE_MODE], [Define default mode for device node])
AC_MSG_CHECKING(when to create device nodes)
AC_ARG_WITH(device-nodes-on,
@@ -260,8 +270,13 @@ AC_ARG_ENABLE(lvm1_fallback,
AC_MSG_RESULT($LVM1_FALLBACK)
if test "$LVM1_FALLBACK" = yes; then
DEFAULT_FALLBACK_TO_LVM1=1
AC_DEFINE([LVM1_FALLBACK], 1, [Define to 1 if 'lvm' should fall back to using LVM1 binaries if device-mapper is missing from the kernel])
else
DEFAULT_FALLBACK_TO_LVM1=0
fi
AC_DEFINE_UNQUOTED(DEFAULT_FALLBACK_TO_LVM1, [$DEFAULT_FALLBACK_TO_LVM1],
[Fall back to LVM1 by default if device-mapper is missing from the kernel.])
################################################################################
dnl -- format1 inclusion type
@@ -549,6 +564,12 @@ case "$CACHE" in
*) AC_MSG_ERROR([--with-cache parameter invalid]) ;;
esac
dnl -- cache_check needs-check flag
AC_ARG_ENABLE(cache_check_needs_check,
AC_HELP_STRING([--disable-cache_check_needs_check],
[required if cache_check version is < 0.5]),
CACHE_CHECK_NEEDS_CHECK=$enableval, CACHE_CHECK_NEEDS_CHECK=yes)
# Test if necessary cache tools are available
# if not - use plain defaults and warn user
case "$CACHE" in
@@ -562,6 +583,21 @@ case "$CACHE" in
CACHE_CONFIGURE_WARN=y
fi
fi
if test "$CACHE_CHECK_NEEDS_CHECK" = yes; then
CACHE_CHECK_VSN=`"$CACHE_CHECK_CMD" -V 2>/dev/null`
CACHE_CHECK_VSN_MAJOR=`echo "$CACHE_CHECK_VSN" | $AWK -F '.' '{print $1}'`
CACHE_CHECK_VSN_MINOR=`echo "$CACHE_CHECK_VSN" | $AWK -F '.' '{print $2}'`
if test -z "$CACHE_CHECK_VSN_MAJOR" -o -z "$CACHE_CHECK_VSN_MINOR"; then
AC_MSG_WARN([$CACHE_CHECK_CMD: Bad version "$CACHE_CHECK_VSN" found])
CACHE_CHECK_VERSION_WARN=y
CACHE_CHECK_NEEDS_CHECK=no
elif test "$CACHE_CHECK_VSN_MAJOR" -eq 0 -a "$CACHE_CHECK_VSN_MINOR" -lt 5; then
AC_MSG_WARN([$CACHE_CHECK_CMD: Old version "$CACHE_CHECK_VSN" found])
CACHE_CHECK_VERSION_WARN=y
CACHE_CHECK_NEEDS_CHECK=no
fi
fi
# Empty means a config way to ignore cache dumping
if test "$CACHE_DUMP_CMD" = "autodetect"; then
AC_PATH_TOOL(CACHE_DUMP_CMD, cache_dump)
@@ -589,6 +625,12 @@ case "$CACHE" in
CACHE_CONFIGURE_WARN=y
}
fi
AC_MSG_CHECKING([whether cache_check supports the needs-check flag])
AC_MSG_RESULT([$CACHE_CHECK_NEEDS_CHECK])
if test "$CACHE_CHECK_NEEDS_CHECK" = yes; then
AC_DEFINE([CACHE_CHECK_NEEDS_CHECK], 1, [Define to 1 if the external 'cache_check' tool requires the --clear-needs-check-flag option])
fi
;;
esac
@@ -617,8 +659,8 @@ AC_MSG_RESULT($READLINE)
dnl -- Disable realtime clock support
AC_MSG_CHECKING(whether to enable realtime support)
AC_ARG_ENABLE(realtime,
AC_HELP_STRING([--enable-realtime], [enable realtime clock support]),
REALTIME=$enableval)
AC_HELP_STRING([--disable-realtime], [disable realtime clock support]),
REALTIME=$enableval, REALTIME=yes)
AC_MSG_RESULT($REALTIME)
################################################################################
@@ -1023,6 +1065,13 @@ if test "$TESTING" = yes; then
PKG_CHECK_MODULES(CUNIT, cunit >= 2.0)
fi
################################################################################
dnl -- Set LVM2 testsuite data
TESTSUITE_DATA='${datarootdir}/lvm2-testsuite'
# double eval needed ${datarootdir} -> ${prefix}/share -> real path
AC_DEFINE_UNQUOTED(TESTSUITE_DATA, ["$(eval echo $(eval echo $TESTSUITE_DATA))"], [Path to testsuite data])
################################################################################
dnl -- Enable valgrind awareness of memory pools
AC_MSG_CHECKING(whether to enable valgrind awareness of pools)
@@ -1068,6 +1117,96 @@ AC_MSG_RESULT($LVMETAD)
BUILD_LVMETAD=$LVMETAD
################################################################################
dnl -- Build lvmpolld
AC_MSG_CHECKING(whether to build lvmpolld)
AC_ARG_ENABLE(lvmpolld,
AC_HELP_STRING([--enable-lvmpolld],
[enable the LVM Polling Daemon]),
LVMPOLLD=$enableval)
AC_MSG_RESULT($LVMPOLLD)
BUILD_LVMPOLLD=$LVMPOLLD
################################################################################
dnl -- Build lockdsanlock
AC_MSG_CHECKING(whether to build lockdsanlock)
AC_ARG_ENABLE(lockd-sanlock,
AC_HELP_STRING([--enable-lockd-sanlock],
[enable the LVM lock daemon using sanlock]),
LOCKDSANLOCK=$enableval)
AC_MSG_RESULT($LOCKDSANLOCK)
BUILD_LOCKDSANLOCK=$LOCKDSANLOCK
if test "$BUILD_LOCKDSANLOCK" = yes; then
AC_DEFINE([LOCKDSANLOCK_SUPPORT], 1, [Define to 1 to include code that uses lvmlockd sanlock option.])
fi
################################################################################
dnl -- Look for sanlock libraries
if test "$BUILD_LOCKDSANLOCK" = yes; then
PKG_CHECK_MODULES(LOCKD_SANLOCK, libsanlock_client, [HAVE_LOCKD_SANLOCK=yes], $bailout)
BUILD_LVMLOCKD=yes
fi
################################################################################
dnl -- Build lockddlm
AC_MSG_CHECKING(whether to build lockddlm)
AC_ARG_ENABLE(lockd-dlm,
AC_HELP_STRING([--enable-lockd-dlm],
[enable the LVM lock daemon using dlm]),
LOCKDDLM=$enableval)
AC_MSG_RESULT($LOCKDDLM)
BUILD_LOCKDDLM=$LOCKDDLM
if test "$BUILD_LOCKDDLM" = yes; then
AC_DEFINE([LOCKDDLM_SUPPORT], 1, [Define to 1 to include code that uses lvmlockd dlm option.])
fi
################################################################################
dnl -- Look for dlm libraries
if test "$BUILD_LOCKDDLM" = yes; then
PKG_CHECK_MODULES(LOCKD_DLM, libdlm, [HAVE_LOCKD_DLM=yes], $bailout)
BUILD_LVMLOCKD=yes
fi
################################################################################
dnl -- Build lvmlockd
AC_MSG_CHECKING(whether to build lvmlockd)
AC_MSG_RESULT($BUILD_LVMLOCKD)
if test "$BUILD_LVMLOCKD" = yes; then
AS_IF([test -n "$BUILD_LVMPOLLD"], [BUILD_LVMPOLLD=yes; AC_MSG_WARN([Enabling lvmpolld - required by lvmlockd.])])
AS_IF([test -n "$BUILD_LVMETAD"], [BUILD_LVMETAD=yes; AC_MSG_WARN([Enabling lvmetad - required by lvmlockd.])])
AC_MSG_CHECKING([defaults for use_lvmlockd])
AC_ARG_ENABLE(use_lvmlockd,
AC_HELP_STRING([--disable-use-lvmlockd],
[disable usage of LVM lock daemon]),
[case ${enableval} in
yes) DEFAULT_USE_LVMLOCKD=1 ;;
*) DEFAULT_USE_LVMLOCKD=0 ;;
esac], DEFAULT_USE_LVMLOCKD=1)
AC_MSG_RESULT($DEFAULT_USE_LVMLOCKD)
AC_DEFINE([LVMLOCKD_SUPPORT], 1, [Define to 1 to include code that uses lvmlockd.])
AC_ARG_WITH(lvmlockd-pidfile,
AC_HELP_STRING([--with-lvmlockd-pidfile=PATH],
[lvmlockd pidfile [PID_DIR/lvmlockd.pid]]),
LVMLOCKD_PIDFILE=$withval,
LVMLOCKD_PIDFILE="$DEFAULT_PID_DIR/lvmlockd.pid")
AC_DEFINE_UNQUOTED(LVMLOCKD_PIDFILE, ["$LVMLOCKD_PIDFILE"],
[Path to lvmlockd pidfile.])
else
DEFAULT_USE_LVMLOCKD=0
fi
AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMLOCKD, [$DEFAULT_USE_LVMLOCKD],
[Use lvmlockd by default.])
################################################################################
dnl -- Check lvmetad
if test "$BUILD_LVMETAD" = yes; then
AC_MSG_CHECKING([defaults for use_lvmetad])
AC_ARG_ENABLE(use_lvmetad,
@@ -1094,16 +1233,7 @@ AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMETAD, [$DEFAULT_USE_LVMETAD],
[Use lvmetad by default.])
################################################################################
dnl -- Build lvmpolld
AC_MSG_CHECKING(whether to build lvmpolld)
AC_ARG_ENABLE(lvmpolld,
AC_HELP_STRING([--enable-lvmpolld],
[enable the LVM Polling Daemon]),
LVMPOLLD=$enableval)
AC_MSG_RESULT($LVMPOLLD)
BUILD_LVMPOLLD=$LVMPOLLD
dnl -- Check lvmpolld
if test "$BUILD_LVMPOLLD" = yes; then
AC_MSG_CHECKING([defaults for use_lvmpolld])
AC_ARG_ENABLE(use_lvmpolld,
@@ -1130,6 +1260,7 @@ AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMPOLLD, [$DEFAULT_USE_LVMPOLLD],
[Use lvmpolld by default.])
################################################################################
dnl -- Enable blkid wiping functionality
AC_MSG_CHECKING(whether to enable libblkid detection of signatures when wiping)
AC_ARG_ENABLE(blkid_wiping,
@@ -1149,9 +1280,16 @@ if test "$BLKID_WIPING" != no; then
fi])
if test "$BLKID_WIPING" = yes; then
BLKID_PC="blkid"
DEFAULT_USE_BLKID_WIPING=1
AC_DEFINE([BLKID_WIPING_SUPPORT], 1, [Define to 1 to use libblkid detection of signatures when wiping.])
else
DEFAULT_USE_BLKID_WIPING=1
fi
else
DEFAULT_USE_BLKID_WIPING=0
fi
AC_DEFINE_UNQUOTED(DEFAULT_USE_BLKID_WIPING, [$DEFAULT_USE_BLKID_WIPING],
[Use blkid wiping by default.])
################################################################################
dnl -- Enable udev-systemd protocol to instantiate a service for background jobs
@@ -1224,11 +1362,11 @@ AC_ARG_ENABLE(compat,
[enable support for old device-mapper versions]),
DM_COMPAT=$enableval, DM_COMPAT=no)
if test "$DM_COMPAT" = yes; then
AC_MSG_ERROR([--enable-compat is not currently supported.
AS_IF([test "$DM_COMPAT" = yes],
[AC_DEFINE([DM_COMPAT], 1, [Define to enable compat protocol])
AC_MSG_ERROR([--enable-compat is not currently supported.
Since device-mapper version 1.02.66, only one version (4) of the device-mapper
ioctl protocol is supported.])
fi
ioctl protocol is supported.])])
################################################################################
dnl -- Compatible units suffix mode
@@ -1248,6 +1386,8 @@ AC_ARG_ENABLE(ioctl,
AC_HELP_STRING([--disable-ioctl],
[disable ioctl calls to device-mapper in the kernel]),
DM_IOCTLS=$enableval)
AS_IF([test "$DM_IOCTLS" = yes],
[AC_DEFINE([DM_IOCTLS], 1, [Define to enable ioctls calls to kernel])])
################################################################################
dnl -- Disable O_DIRECT
@@ -1430,9 +1570,11 @@ if test "$REALTIME" = yes; then
if test "$HAVE_REALTIME" = yes; then
AC_DEFINE([HAVE_REALTIME], 1, [Define to 1 to include support for realtime clock.])
LIBS="-lrt $LIBS"
RT_PC="librt"
else
AC_MSG_WARN(Disabling realtime clock)
fi
AC_MSG_RESULT($HAVE_REALTIME)
fi
dnl Check if the system has struct stat st_ctim.
@@ -1506,14 +1648,16 @@ if test "$INTL" = yes; then
# FIXME - Move this - can be device-mapper too
INTL_PACKAGE="lvm2"
AC_PATH_TOOL(MSGFMT, msgfmt)
if [[ -z "$MSGFMT" ]]; then
AC_MSG_ERROR([msgfmt not found in path $PATH])
fi
AS_IF([test -z "$MSGFMT"], [AC_MSG_ERROR([msgfmt not found in path $PATH])])
AC_ARG_WITH(localedir,
AC_HELP_STRING([--with-localedir=DIR],
[translation files in DIR [PREFIX/share/locale]]),
LOCALEDIR=$withval, LOCALEDIR='${prefix}/share/locale')
[locale-dependent data [DATAROOTDIR/locale]]),
localedir=$withval, localedir=${localedir-'${datarootdir}/locale'})
AC_DEFINE_UNQUOTED([INTL_PACKAGE], ["$INTL_PACKAGE"], [Internalization package])
# double eval needed ${datarootdir} -> ${prefix}/share -> real path
AC_DEFINE_UNQUOTED([LOCALEDIR], ["$(eval echo $(eval echo $localedir))"], [Locale-dependent data])
fi
################################################################################
@@ -1578,6 +1722,19 @@ if test "$READLINE" = yes; then
AC_CHECK_HEADERS(readline/readline.h readline/history.h,,hard_bailout)
fi
if test "$BUILD_CMIRRORD" = yes; then
AC_CHECK_FUNCS(atexit,,hard_bailout)
fi
if test "$BUILD_LVMLOCKD" = yes; then
AC_CHECK_FUNCS(clock_gettime strtoull,,hard_bailout)
fi
if test "$BUILD_LVMPOLLD" = yes; then
AC_CHECK_FUNCS(strpbrk,,hard_bailout)
AC_FUNC_STRERROR_R
fi
if test "$CLVMD" != none; then
AC_CHECK_HEADERS(mntent.h netdb.h netinet/in.h pthread.h search.h sys/mount.h sys/socket.h sys/uio.h sys/un.h utmpx.h,,AC_MSG_ERROR(bailing out))
AC_CHECK_FUNCS(dup2 getmntent memmove select socket,,hard_bailout)
@@ -1735,11 +1892,13 @@ LVM_LIBAPI=`echo "$VER" | $AWK -F '[[()]]' '{print $2}'`
AC_SUBST(APPLIB)
AC_SUBST(AWK)
AC_SUBST(BLKID_PC)
AC_SUBST(BLKID_WIPING)
AC_SUBST(BUILD_CMIRRORD)
AC_SUBST(BUILD_DMEVENTD)
AC_SUBST(BUILD_LVMETAD)
AC_SUBST(BUILD_LVMPOLLD)
AC_SUBST(BUILD_LVMLOCKD)
AC_SUBST(BUILD_LOCKDSANLOCK)
AC_SUBST(BUILD_LOCKDDLM)
AC_SUBST(CACHE)
AC_SUBST(CFLAGS)
AC_SUBST(CFLOW_CMD)
@@ -1769,6 +1928,7 @@ AC_SUBST(DEFAULT_CACHE_SUBDIR)
AC_SUBST(DEFAULT_DATA_ALIGNMENT)
AC_SUBST(DEFAULT_DM_RUN_DIR)
AC_SUBST(DEFAULT_LOCK_DIR)
AC_SUBST(DEFAULT_FALLBACK_TO_LVM1)
AC_SUBST(DEFAULT_MIRROR_SEGTYPE)
AC_SUBST(DEFAULT_PID_DIR)
AC_SUBST(DEFAULT_PROFILE_SUBDIR)
@@ -1776,19 +1936,16 @@ AC_SUBST(DEFAULT_RAID10_SEGTYPE)
AC_SUBST(DEFAULT_RUN_DIR)
AC_SUBST(DEFAULT_SPARSE_SEGTYPE)
AC_SUBST(DEFAULT_SYS_DIR)
AC_SUBST(DEFAULT_USE_BLKID_WIPING)
AC_SUBST(DEFAULT_USE_LVMETAD)
AC_SUBST(DEFAULT_USE_LVMPOLLD)
AC_SUBST(DEFAULT_USE_LVMLOCKD)
AC_SUBST(DEVMAPPER)
AC_SUBST(DLM_CFLAGS)
AC_SUBST(DLM_LIBS)
AC_SUBST(DL_LIBS)
AC_SUBST(DMEVENTD)
AC_SUBST(DMEVENTD_PATH)
AC_SUBST(DM_COMPAT)
AC_SUBST(DM_DEVICE_GID)
AC_SUBST(DM_DEVICE_MODE)
AC_SUBST(DM_DEVICE_UID)
AC_SUBST(DM_IOCTLS)
AC_SUBST(DM_LIB_VERSION)
AC_SUBST(DM_LIB_PATCHLEVEL)
AC_SUBST(ELDFLAGS)
@@ -1798,12 +1955,10 @@ AC_SUBST(HAVE_LIBDL)
AC_SUBST(HAVE_REALTIME)
AC_SUBST(HAVE_VALGRIND)
AC_SUBST(INTL)
AC_SUBST(INTL_PACKAGE)
AC_SUBST(JOBS)
AC_SUBST(LDDEPS)
AC_SUBST(LIBS)
AC_SUBST(LIB_SUFFIX)
AC_SUBST(LOCALEDIR)
AC_SUBST(LVM1)
AC_SUBST(LVM1_FALLBACK)
AC_SUBST(LVM_VERSION)
@@ -1814,6 +1969,7 @@ AC_SUBST(LVM_PATCHLEVEL)
AC_SUBST(LVM_PATH)
AC_SUBST(LVM_RELEASE)
AC_SUBST(LVM_RELEASE_DATE)
AC_SUBST(localedir)
AC_SUBST(MANGLING)
AC_SUBST(MIRRORS)
AC_SUBST(MSGFMT)
@@ -1829,6 +1985,7 @@ AC_SUBST(PYTHON_LIBDIRS)
AC_SUBST(QUORUM_CFLAGS)
AC_SUBST(QUORUM_LIBS)
AC_SUBST(RAID)
AC_SUBST(RT_PC)
AC_SUBST(READLINE_LIBS)
AC_SUBST(REPLICATORS)
AC_SUBST(SACKPT_CFLAGS)
@@ -1841,6 +1998,7 @@ AC_SUBST(SNAPSHOTS)
AC_SUBST(STATICDIR)
AC_SUBST(STATIC_LINK)
AC_SUBST(TESTING)
AC_SUBST(TESTSUITE_DATA)
AC_SUBST(THIN)
AC_SUBST(THIN_CHECK_CMD)
AC_SUBST(THIN_DUMP_CMD)
@@ -1861,6 +2019,7 @@ AC_SUBST(WRITE_INSTALL)
AC_SUBST(DMEVENTD_PIDFILE)
AC_SUBST(LVMETAD_PIDFILE)
AC_SUBST(LVMPOLLD_PIDFILE)
AC_SUBST(LVMLOCKD_PIDFILE)
AC_SUBST(CLVMD_PIDFILE)
AC_SUBST(CMIRRORD_PIDFILE)
AC_SUBST(interface)
@@ -1895,6 +2054,7 @@ 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
@@ -1941,6 +2101,8 @@ 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

View File

@@ -15,7 +15,7 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
.PHONY: dmeventd clvmd cmirrord lvmetad lvmpolld
.PHONY: dmeventd clvmd cmirrord lvmetad lvmpolld lvmlockd
ifneq ("@CLVMD@", "none")
SUBDIRS += clvmd
@@ -40,8 +40,12 @@ ifeq ("@BUILD_LVMPOLLD@", "yes")
SUBDIRS += lvmpolld
endif
ifeq ("@BUILD_LVMLOCKD@", "yes")
SUBDIRS += lvmlockd
endif
ifeq ($(MAKECMDGOALS),distclean)
SUBDIRS = clvmd cmirrord dmeventd lvmetad lvmpolld
SUBDIRS = clvmd cmirrord dmeventd lvmetad lvmpolld lvmlockd
endif
include $(top_builddir)/make.tmpl

1
daemons/clvmd/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
clvmd

View File

@@ -323,6 +323,7 @@ void cmd_client_cleanup(struct local_client *client)
int lkid;
char *lockname;
DEBUGLOG("Client thread cleanup (%p)\n", client);
if (!client->bits.localsock.private)
return;
@@ -331,7 +332,7 @@ void cmd_client_cleanup(struct local_client *client)
dm_hash_iterate(v, lock_hash) {
lkid = (int)(long)dm_hash_get_data(lock_hash, v);
lockname = dm_hash_get_key(lock_hash, v);
DEBUGLOG("cleanup: Unlocking lock %s %x\n", lockname, lkid);
DEBUGLOG("Cleanup (%p): Unlocking lock %s %x\n", client, lockname, lkid);
(void) sync_unlock(lockname, lkid);
}
@@ -339,7 +340,6 @@ void cmd_client_cleanup(struct local_client *client)
client->bits.localsock.private = NULL;
}
static int restart_clvmd(void)
{
const char **argv;

View File

@@ -18,15 +18,10 @@
#ifndef _LVM_CLVMD_COMMON_H
#define _LVM_CLVMD_COMMON_H
#include "configure.h"
#define _REENTRANT
#define _GNU_SOURCE
#define _FILE_OFFSET_BITS 64
#include "libdevmapper.h"
#include "tool.h"
#include "lvm-logging.h"
#include <unistd.h>
#endif

View File

@@ -243,7 +243,7 @@ static void openais_cpg_confchg_callback(cpg_handle_t handle,
struct node_info *ninfo;
DEBUGLOG("confchg callback. %" PRIsize_t " joined, "
"%" PRIsize_t " left, %" PRIsize_t " members\n",
FMTsize_t " left, %" PRIsize_t " members\n",
joined_list_entries, left_list_entries, member_list_entries);
for (i=0; i<joined_list_entries; i++) {

View File

@@ -223,6 +223,7 @@ void debuglog(const char *fmt, ...)
fprintf(stderr, "CLVMD[%x]: %.15s ", (int)pthread_self(), ctime_r(&P, buf_ctime) + 4);
vfprintf(stderr, fmt, ap);
va_end(ap);
fflush(stderr);
break;
case DEBUG_SYSLOG:
if (!syslog_init) {
@@ -598,7 +599,9 @@ int main(int argc, char *argv[])
/* This needs to be started after cluster initialisation
as it may need to take out locks */
DEBUGLOG("starting LVM thread\n");
DEBUGLOG("Starting LVM thread\n");
DEBUGLOG("Main cluster socket fd %d (%p) with local socket %d (%p)\n",
local_client_head.fd, &local_client_head, newfd->fd, newfd);
/* Don't let anyone else to do work until we are started */
pthread_create(&lvm_thread, &stack_attr, lvm_thread_fn, &lvm_params);
@@ -698,7 +701,7 @@ static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
newfd->type = LOCAL_SOCK;
newfd->callback = local_sock_callback;
newfd->bits.localsock.all_success = 1;
DEBUGLOG("Got new connection on fd %d\n", newfd->fd);
DEBUGLOG("Got new connection on fd %d (%p)\n", newfd->fd, newfd);
*new_client = newfd;
}
return 1;
@@ -850,18 +853,48 @@ static void main_loop(int cmd_timeout)
struct local_client *thisfd;
struct timeval tv = { cmd_timeout, 0 };
int quorate = clops->is_quorate();
int client_count = 0;
int max_fd = 0;
/* Wait on the cluster FD and all local sockets/pipes */
local_client_head.fd = clops->get_main_cluster_fd();
FD_ZERO(&in);
struct local_client *lastfd = &local_client_head;
struct local_client *nextfd = local_client_head.next;
for (thisfd = &local_client_head; thisfd; thisfd = thisfd->next) {
client_count++;
max_fd = max(max_fd, thisfd->fd);
}
if (max_fd > FD_SETSIZE - 32) {
fprintf(stderr, "WARNING: There are too many connections to clvmd. Investigate and take action now!\n");
fprintf(stderr, "WARNING: Your cluster may freeze up if the number of clvmd file descriptors (%d) exceeds %d.\n", max_fd + 1, FD_SETSIZE);
}
for (thisfd = &local_client_head; thisfd; thisfd = nextfd, nextfd = thisfd ? thisfd->next : NULL) {
if (thisfd->removeme && !cleanup_zombie(thisfd)) {
struct local_client *free_fd = thisfd;
lastfd->next = nextfd;
DEBUGLOG("removeme set for %p with %d monitored fds remaining\n", free_fd, client_count - 1);
/* Queue cleanup, this also frees the client struct */
add_to_lvmqueue(free_fd, NULL, 0, NULL);
continue;
}
lastfd = thisfd;
if (thisfd->removeme)
continue;
/* if the cluster is not quorate then don't listen for new requests */
if ((thisfd->type != LOCAL_RENDEZVOUS &&
thisfd->type != LOCAL_SOCK) || quorate)
FD_SET(thisfd->fd, &in);
if (thisfd->fd < FD_SETSIZE)
FD_SET(thisfd->fd, &in);
}
select_status = select(FD_SETSIZE, &in, NULL, NULL, &tv);
@@ -877,31 +910,20 @@ static void main_loop(int cmd_timeout)
}
if (select_status > 0) {
struct local_client *lastfd = NULL;
char csid[MAX_CSID_LEN];
char buf[max_cluster_message];
for (thisfd = &local_client_head; thisfd; thisfd = thisfd->next) {
if (thisfd->removeme && !cleanup_zombie(thisfd)) {
struct local_client *free_fd = thisfd;
lastfd->next = thisfd->next;
DEBUGLOG("removeme set for fd %d\n", free_fd->fd);
/* Queue cleanup, this also frees the client struct */
add_to_lvmqueue(free_fd, NULL, 0, NULL);
break;
}
if (FD_ISSET(thisfd->fd, &in)) {
if (thisfd->fd < FD_SETSIZE && FD_ISSET(thisfd->fd, &in)) {
struct local_client *newfd = NULL;
int ret;
/* FIXME Remove from main thread in case it blocks! */
/* Do callback */
ret = thisfd->callback(thisfd, buf, sizeof(buf),
csid, &newfd);
/* Ignore EAGAIN */
if (ret < 0 && (errno == EAGAIN || errno == EINTR)) {
lastfd = thisfd;
continue;
}
@@ -917,17 +939,16 @@ static void main_loop(int cmd_timeout)
DEBUGLOG("ret == %d, errno = %d. removing client\n",
ret, errno);
thisfd->removeme = 1;
break;
continue;
}
/* New client...simply add it to the list */
if (newfd) {
newfd->next = thisfd->next;
thisfd->next = newfd;
break;
thisfd = newfd;
}
}
lastfd = thisfd;
}
}
@@ -1420,7 +1441,7 @@ static int read_from_local_sock(struct local_client *thisfd)
thisfd->bits.localsock.in_progress = TRUE;
thisfd->bits.localsock.state = PRE_COMMAND;
thisfd->bits.localsock.cleanup_needed = 1;
DEBUGLOG("Creating pre&post thread\n");
DEBUGLOG("Creating pre&post thread for pipe fd %d (%p)\n", newfd->fd, newfd);
status = pthread_create(&thisfd->bits.localsock.threadid,
&stack_attr, pre_and_post_thread, thisfd);
DEBUGLOG("Created pre&post thread, state = %d\n", status);
@@ -1674,7 +1695,7 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
sigset_t ss;
int pipe_fd = client->bits.localsock.pipe;
DEBUGLOG("Pre&post thread (%p), pipe %d\n", client, pipe_fd);
DEBUGLOG("Pre&post thread (%p), pipe fd %d\n", client, pipe_fd);
pthread_mutex_lock(&client->bits.localsock.mutex);
/* Ignore SIGUSR1 (handled by master process) but enable
@@ -1694,7 +1715,7 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
if ((status = do_pre_command(client)))
client->bits.localsock.all_success = 0;
DEBUGLOG("Pre&post thread (%p) writes status %d down to pipe %d\n",
DEBUGLOG("Pre&post thread (%p) writes status %d down to pipe fd %d\n",
client, status, pipe_fd);
/* Tell the parent process we have finished this bit */
@@ -1976,7 +1997,7 @@ static int process_work_item(struct lvm_thread_cmd *cmd)
{
/* If msg is NULL then this is a cleanup request */
if (cmd->msg == NULL) {
DEBUGLOG("process_work_item: free fd %d\n", cmd->client->fd);
DEBUGLOG("process_work_item: free %p\n", cmd->client);
cmd_client_cleanup(cmd->client);
pthread_mutex_destroy(&cmd->client->bits.localsock.mutex);
pthread_cond_destroy(&cmd->client->bits.localsock.cond);

View File

@@ -510,7 +510,7 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
DEBUGLOG("do_lock_lv: resource '%s', cmd = %s, flags = %s, critical_section = %d\n",
resource, decode_locking_cmd(command), decode_flags(lock_flags), critical_section());
if (!cmd->config_initialized || config_files_changed(cmd)) {
if (!cmd->initialized.config || config_files_changed(cmd)) {
/* Reinitialise various settings inc. logging, filters */
if (do_refresh_cache()) {
log_error("Updated config file invalid. Aborting.");
@@ -899,7 +899,7 @@ int init_clvm(struct dm_hash_table *excl_uuid)
if (!get_initial_state(excl_uuid))
log_error("Cannot load initial lock states.");
if (!(cmd = create_toolcontext(1, NULL, 0, 1))) {
if (!(cmd = create_toolcontext(1, NULL, 0, 1, 1, 1))) {
log_error("Failed to allocate command context");
return 0;
}

1
daemons/cmirrord/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
cmirrord

1
daemons/dmeventd/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
dmeventd

View File

@@ -16,26 +16,21 @@
* dmeventd - dm event daemon to monitor active mapped devices
*/
#define _GNU_SOURCE
#define _FILE_OFFSET_BITS 64
#include "tool.h"
#include "configure.h"
#include "libdevmapper.h"
#include "libdevmapper-event.h"
#include "dmeventd.h"
//#include "libmultilog.h"
#include "dm-logging.h"
#include <stdarg.h>
#include "libdevmapper-event.h"
#include "dmeventd.h"
#include <dlfcn.h>
#include <errno.h>
#include <pthread.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <signal.h>
#include <arpa/inet.h> /* for htonl, ntohl */
#include <fcntl.h> /* for musl libc */
@@ -133,51 +128,20 @@ void debuglog(const char *fmt, ...)
static const char *decode_cmd(uint32_t cmd)
{
static char buf[128];
const char *command;
switch (cmd) {
case DM_EVENT_CMD_ACTIVE:
command = "ACTIVE";
break;
case DM_EVENT_CMD_REGISTER_FOR_EVENT:
command = "REGISTER_FOR_EVENT";
break;
case DM_EVENT_CMD_UNREGISTER_FOR_EVENT:
command = "UNREGISTER_FOR_EVENT";
break;
case DM_EVENT_CMD_GET_REGISTERED_DEVICE:
command = "GET_REGISTERED_DEVICE";
break;
case DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE:
command = "GET_NEXT_REGISTERED_DEVICE";
break;
case DM_EVENT_CMD_SET_TIMEOUT:
command = "SET_TIMEOUT";
break;
case DM_EVENT_CMD_GET_TIMEOUT:
command = "GET_TIMEOUT";
break;
case DM_EVENT_CMD_HELLO:
command = "HELLO";
break;
case DM_EVENT_CMD_DIE:
command = "DIE";
break;
case DM_EVENT_CMD_GET_STATUS:
command = "GET_STATUS";
break;
case DM_EVENT_CMD_GET_PARAMETERS:
command = "GET_PARAMETERS";
break;
default:
command = "unknown";
break;
case DM_EVENT_CMD_ACTIVE: return "ACTIVE";
case DM_EVENT_CMD_REGISTER_FOR_EVENT: return "REGISTER_FOR_EVENT";
case DM_EVENT_CMD_UNREGISTER_FOR_EVENT: return "UNREGISTER_FOR_EVENT";
case DM_EVENT_CMD_GET_REGISTERED_DEVICE: return "GET_REGISTERED_DEVICE";
case DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE: return "GET_NEXT_REGISTERED_DEVICE";
case DM_EVENT_CMD_SET_TIMEOUT: return "SET_TIMEOUT";
case DM_EVENT_CMD_GET_TIMEOUT: return "GET_TIMEOUT";
case DM_EVENT_CMD_HELLO: return "HELLO";
case DM_EVENT_CMD_DIE: return "DIE";
case DM_EVENT_CMD_GET_STATUS: return "GET_STATUS";
case DM_EVENT_CMD_GET_PARAMETERS: return "GET_PARAMETERS";
default: return "unknown";
}
snprintf(buf, sizeof(buf), "%s (0x%x)", command, cmd);
return buf;
}
#else
@@ -710,6 +674,7 @@ static int _event_wait(struct thread_status *thread, struct dm_task **task)
int ret = DM_WAIT_RETRY;
struct dm_task *dmt;
struct dm_info info;
int ioctl_errno;
*task = 0;
@@ -739,25 +704,27 @@ static int _event_wait(struct thread_status *thread, struct dm_task **task)
* either for a timeout event, or to cancel the thread.
*/
set = _unblock_sigalrm();
errno = 0;
if (dm_task_run(dmt)) {
thread->current_events |= DM_EVENT_DEVICE_ERROR;
ret = DM_WAIT_INTR;
if ((ret = dm_task_get_info(dmt, &info)))
thread->event_nr = info.event_nr;
} else if (thread->events & DM_EVENT_TIMEOUT && errno == EINTR) {
thread->current_events |= DM_EVENT_TIMEOUT;
ret = DM_WAIT_INTR;
} else if (thread->status == DM_THREAD_SHUTDOWN && errno == EINTR) {
ret = DM_WAIT_FATAL;
} else {
syslog(LOG_NOTICE, "dm_task_run failed, errno = %d, %s",
errno, strerror(errno));
if (errno == ENXIO) {
syslog(LOG_ERR, "%s disappeared, detaching",
thread->device.name);
ioctl_errno = dm_task_get_errno(dmt);
if (thread->events & DM_EVENT_TIMEOUT && ioctl_errno == EINTR) {
thread->current_events |= DM_EVENT_TIMEOUT;
ret = DM_WAIT_INTR;
} else if (thread->status == DM_THREAD_SHUTDOWN && ioctl_errno == EINTR)
ret = DM_WAIT_FATAL;
else {
syslog(LOG_NOTICE, "dm_task_run failed, errno = %d, %s",
ioctl_errno, strerror(ioctl_errno));
if (ioctl_errno == ENXIO) {
syslog(LOG_ERR, "%s disappeared, detaching",
thread->device.name);
ret = DM_WAIT_FATAL;
}
}
}
DEBUGLOG("Completed waitevent task for %s", thread->device.uuid);
@@ -1595,9 +1562,6 @@ static void _process_request(struct dm_event_fifos *fifos)
{
int die;
struct dm_event_daemon_message msg = { 0 };
#ifdef DEBUG
const char *cmd;
#endif
/*
* Read the request from the client (client_read, client_write
@@ -1606,7 +1570,8 @@ static void _process_request(struct dm_event_fifos *fifos)
if (!_client_read(fifos, &msg))
return;
DEBUGLOG("%s processing...", cmd = decode_cmd(msg.cmd));
DEBUGLOG("%s (0x%x) processing...", decode_cmd(msg.cmd), msg.cmd);
die = (msg.cmd == DM_EVENT_CMD_DIE) ? 1 : 0;
/* _do_process_request fills in msg (if memory allows for
@@ -1618,7 +1583,7 @@ static void _process_request(struct dm_event_fifos *fifos)
dm_free(msg.data);
DEBUGLOG("%s completed.", cmd);
DEBUGLOG("%s (0x%x) completed.", decode_cmd(msg.cmd), msg.cmd);
if (die) {
if (unlink(DMEVENTD_PIDFILE))
@@ -1668,10 +1633,8 @@ static void _cleanup_unused_threads(void)
if (ret == ESRCH) {
thread->status = DM_THREAD_DONE;
} else if (ret) {
syslog(LOG_ERR,
"Unable to terminate thread: %s\n",
strerror(-ret));
stack;
syslog(LOG_ERR, "Unable to terminate thread: %s",
strerror(ret));
}
break;
}
@@ -1703,8 +1666,7 @@ static void _cleanup_unused_threads(void)
static void _sig_alarm(int signum __attribute__((unused)))
{
DEBUGLOG("Received SIGALRM.");
pthread_testcancel();
/* empty SIG_IGN */;
}
/* Init thread signal handling. */

View File

@@ -17,15 +17,10 @@
//#include "libmultilog.h"
#include "dmeventd.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/wait.h>
#include <arpa/inet.h> /* for htonl, ntohl */

2
daemons/lvmetad/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
lvmetad
lvmetactl

View File

@@ -18,7 +18,7 @@ top_builddir = @top_builddir@
SOURCES = lvmetad-core.c
SOURCES2 = testclient.c
TARGETS = lvmetad
TARGETS = lvmetad lvmetactl
.PHONY: install_lvmetad
@@ -39,8 +39,11 @@ CFLAGS += $(EXTRA_EXEC_CFLAGS)
lvmetad: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
$(top_builddir)/libdaemon/server/libdaemonserver.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \
$(DL_LIBS) $(LVMLIBS) $(LIBS) -rdynamic
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LVMLIBS) $(LIBS)
lvmetactl: lvmetactl.o $(top_builddir)/libdaemon/client/libdaemonclient.a \
$(top_builddir)/libdaemon/server/libdaemonserver.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmetactl.o $(LVMLIBS)
# TODO: No idea. No idea how to test either.
#ifneq ("$(CFLOW_CMD)", "")

183
daemons/lvmetad/lvmetactl.c Normal file
View File

@@ -0,0 +1,183 @@
/*
* Copyright (C) 2014 Red Hat, Inc.
*
* 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.
*/
#include "tool.h"
#include "lvmetad-client.h"
daemon_handle h;
static void print_reply(daemon_reply reply)
{
const char *a = daemon_reply_str(reply, "response", NULL);
const char *b = daemon_reply_str(reply, "status", NULL);
const char *c = daemon_reply_str(reply, "reason", NULL);
printf("response \"%s\" status \"%s\" reason \"%s\"\n",
a ? a : "", b ? b : "", c ? c : "");
}
int main(int argc, char **argv)
{
daemon_reply reply;
char *cmd;
char *uuid;
char *name;
int val;
int ver;
if (argc < 2) {
printf("lvmeta dump\n");
printf("lvmeta pv_list\n");
printf("lvmeta vg_list\n");
printf("lvmeta vg_lookup_name <name>\n");
printf("lvmeta vg_lookup_uuid <uuid>\n");
printf("lvmeta pv_lookup_uuid <uuid>\n");
printf("lvmeta set_global_invalid 0|1\n");
printf("lvmeta get_global_invalid\n");
printf("lvmeta set_vg_version <uuid> <version>\n");
printf("lvmeta vg_lock_type <uuid>\n");
return -1;
}
cmd = argv[1];
h = lvmetad_open(NULL);
if (!strcmp(cmd, "dump")) {
reply = daemon_send_simple(h, "dump",
"token = %s", "skip",
NULL);
printf("%s\n", reply.buffer.mem);
} else if (!strcmp(cmd, "pv_list")) {
reply = daemon_send_simple(h, "pv_list",
"token = %s", "skip",
NULL);
printf("%s\n", reply.buffer.mem);
} else if (!strcmp(cmd, "vg_list")) {
reply = daemon_send_simple(h, "vg_list",
"token = %s", "skip",
NULL);
printf("%s\n", reply.buffer.mem);
} else if (!strcmp(cmd, "set_global_invalid")) {
if (argc < 3) {
printf("set_global_invalid 0|1\n");
return -1;
}
val = atoi(argv[2]);
reply = daemon_send_simple(h, "set_global_info",
"global_invalid = %d", val,
"token = %s", "skip",
NULL);
print_reply(reply);
} else if (!strcmp(cmd, "get_global_invalid")) {
reply = daemon_send_simple(h, "get_global_info",
"token = %s", "skip",
NULL);
printf("%s\n", reply.buffer.mem);
} else if (!strcmp(cmd, "set_vg_version")) {
if (argc < 4) {
printf("set_vg_version <uuid> <ver>\n");
return -1;
}
uuid = argv[2];
ver = atoi(argv[3]);
reply = daemon_send_simple(h, "set_vg_info",
"uuid = %s", uuid,
"version = %d", ver,
"token = %s", "skip",
NULL);
print_reply(reply);
} else if (!strcmp(cmd, "vg_lookup_name")) {
if (argc < 3) {
printf("vg_lookup_name <name>\n");
return -1;
}
name = argv[2];
reply = daemon_send_simple(h, "vg_lookup",
"name = %s", name,
"token = %s", "skip",
NULL);
printf("%s\n", reply.buffer.mem);
} else if (!strcmp(cmd, "vg_lookup_uuid")) {
if (argc < 3) {
printf("vg_lookup_uuid <uuid>\n");
return -1;
}
uuid = argv[2];
reply = daemon_send_simple(h, "vg_lookup",
"uuid = %s", uuid,
"token = %s", "skip",
NULL);
printf("%s\n", reply.buffer.mem);
} else if (!strcmp(cmd, "vg_lock_type")) {
struct dm_config_node *metadata;
const char *lock_type;
if (argc < 3) {
printf("vg_lock_type <uuid>\n");
return -1;
}
uuid = argv[2];
reply = daemon_send_simple(h, "vg_lookup",
"uuid = %s", uuid,
"token = %s", "skip",
NULL);
/* printf("%s\n", reply.buffer.mem); */
metadata = dm_config_find_node(reply.cft->root, "metadata");
if (!metadata) {
printf("no metadata\n");
goto out;
}
lock_type = dm_config_find_str(metadata, "metadata/lock_type", NULL);
if (!lock_type) {
printf("no lock_type\n");
goto out;
}
printf("lock_type %s\n", lock_type);
} else if (!strcmp(cmd, "pv_lookup_uuid")) {
if (argc < 3) {
printf("pv_lookup_uuid <uuid>\n");
return -1;
}
uuid = argv[2];
reply = daemon_send_simple(h, "pv_lookup",
"uuid = %s", uuid,
"token = %s", "skip",
NULL);
printf("%s\n", reply.buffer.mem);
} else {
printf("unknown command\n");
goto out_close;
}
out:
daemon_reply_destroy(reply);
out_close:
daemon_close(h);
return 0;
}

View File

@@ -14,23 +14,114 @@
#define _XOPEN_SOURCE 500 /* pthread */
#include "configure.h"
#define _REENTRANT
#include "tool.h"
#include "daemon-io.h"
#include "config-util.h"
#include "daemon-server.h"
#include "daemon-log.h"
#include "lvm-version.h"
#include <assert.h>
#include <pthread.h>
#include <stdint.h>
#include <unistd.h>
#include <math.h> /* fabs() */
#include <float.h> /* DBL_EPSILON */
#define LVMETAD_SOCKET DEFAULT_RUN_DIR "/lvmetad.socket"
/*
* valid/invalid state of cached metadata
*
* Normally when using lvmetad, the state is kept up-to-date through a
* combination of notifications from clients and updates triggered by uevents.
* When using lvmlockd, the lvmetad state is expected to become out of
* date (invalid/stale) when other hosts make changes to the metadata on disk.
*
* To deal with this, the metadata cached in lvmetad can be flagged as invalid.
* This invalid flag is returned along with the metadata when read by a
* command. The command can check for the invalid flag and decide that it
* should either use the stale metadata (uncommon), or read the latest metadata
* from disk rather than using the invalid metadata that was returned. If the
* command reads the latest metadata from disk, it can choose to send it to
* lvmetad to update the cached copy and clear the invalid flag in lvmetad.
* Otherwise, the next command to read the metadata from lvmetad will also
* receive the invalid metadata with the invalid flag (and like the previous
* command, it too may choose to read the latest metadata from disk and can
* then also choose to update the lvmetad copy.)
*
* For purposes of tracking the invalid state, LVM metadata is considered
* to be either VG-specific or global. VG-specific metadata is metadata
* that is isolated to a VG, such as the LVs it contains. Global
* metadata is metadata that is not isolated to a single VG. Global
* metdata includes:
* . the VG namespace (which VG names are used)
* . the set of orphan PVs (which PVs are in VGs and which are not)
* . properties of orphan PVs (the size of an orphan PV)
*
* If the metadata for a single VG becomes invalid, the VGFL_INVALID
* flag can be set in the vg_info struct for that VG. If the global
* metdata becomes invalid, the GLFL_INVALID flag can be set in the
* lvmetad daemon state.
*
* If a command reads VG metadata and VGFL_INVALID is set, an
* extra config node called "vg_invalid" is added to the config
* data returned to the command.
*
* If a command reads global metdata and GLFL_INVALID is set, an
* extra config node called "global_invalid" is added to the
* config data returned to the command.
*
* If a command sees vg_invalid, and wants the latest VG metadata,
* it only needs to scan disks of the PVs in that VG.
* It can then use vg_update to send the latest metadata to lvmetad
* which clears the VGFL_INVALID flag.
*
* If a command sees global_invalid, and wants the latest metadata,
* it should scan all devices to update lvmetad, and then send
* lvmetad the "set_global_info global_invalid=0" message to clear
* GLFL_INVALID.
*
* (When rescanning devices to update lvmetad, the command must use
* the global filter cmd->lvmetad_filter so that it processes the same
* devices that are seen by lvmetad.)
*
* The lvmetad INVALID flags can be set by sending lvmetad the messages:
*
* . set_vg_info with the latest VG seqno. If the VG seqno is larger
* than the cached VG seqno, VGFL_INVALID is set for the VG.
*
* . set_global_info with global_invalid=1 sets GLFL_INVALID.
*
* Different entities could use these functions to invalidate metadata
* if/when they detected that the cache is stale. How they detect that
* the cache is stale depends on the details of the specific entity.
*
* In the case of lvmlockd, it embeds values into its locks to keep track
* of when other nodes have changed metadata on disk related to those locks.
* When acquring locks it can look at these values and detect that
* the metadata associated with the lock has been changed.
* When the values change, it uses set_vg_info/set_global_info to
* invalidate the lvmetad cache.
*
* The values that lvmlockd distributes through its locks are the
* latest VG seqno in VG locks and a global counter in the global lock.
* When a host acquires a VG lock and sees that the embedded seqno is
* larger than it was previously, it knows that it should invalidate the
* lvmetad cache for the VG. If the host acquires the global lock
* and sees that the counter is larger than previously, it knows that
* it should invalidate the global info in lvmetad. This invalidation
* is done before the lock is returned to the command. This way the
* invalid flag will be set on the metadata before the command reads
* it from lvmetad.
*/
struct vg_info {
int64_t external_version;
uint32_t flags; /* VGFL_ */
};
#define GLFL_INVALID 0x00000001
#define VGFL_INVALID 0x00000001
typedef struct {
log_state *log; /* convenience */
const char *log_config;
@@ -40,6 +131,8 @@ typedef struct {
struct dm_hash_table *vgid_to_metadata;
struct dm_hash_table *vgid_to_vgname;
struct dm_hash_table *vgid_to_outdated_pvs;
struct dm_hash_table *vgid_to_info;
struct dm_hash_table *vgname_to_vgid;
struct dm_hash_table *pvid_to_vgid;
struct {
@@ -50,6 +143,7 @@ typedef struct {
pthread_mutex_t pvid_to_vgid;
} lock;
char token[128];
uint32_t flags; /* GLFL_ */
pthread_mutex_t token_lock;
} lvmetad_state;
@@ -60,12 +154,17 @@ static void destroy_metadata_hashes(lvmetad_state *s)
dm_hash_iterate(n, s->vgid_to_metadata)
dm_config_destroy(dm_hash_get_data(s->vgid_to_metadata, n));
dm_hash_iterate(n, s->vgid_to_outdated_pvs)
dm_config_destroy(dm_hash_get_data(s->vgid_to_outdated_pvs, n));
dm_hash_iterate(n, s->pvid_to_pvmeta)
dm_config_destroy(dm_hash_get_data(s->pvid_to_pvmeta, n));
dm_hash_destroy(s->pvid_to_pvmeta);
dm_hash_destroy(s->vgid_to_metadata);
dm_hash_destroy(s->vgid_to_vgname);
dm_hash_destroy(s->vgid_to_outdated_pvs);
dm_hash_destroy(s->vgid_to_info);
dm_hash_destroy(s->vgname_to_vgid);
dm_hash_destroy(s->device_to_pvid);
@@ -78,6 +177,8 @@ static void create_metadata_hashes(lvmetad_state *s)
s->device_to_pvid = dm_hash_create(32);
s->vgid_to_metadata = dm_hash_create(32);
s->vgid_to_vgname = dm_hash_create(32);
s->vgid_to_outdated_pvs = dm_hash_create(32);
s->vgid_to_info = dm_hash_create(32);
s->pvid_to_vgid = dm_hash_create(32);
s->vgname_to_vgid = dm_hash_create(32);
}
@@ -241,6 +342,30 @@ static int update_pv_status(lvmetad_state *s,
return complete;
}
static struct dm_config_node *add_last_node(struct dm_config_tree *cft, const char *node_name)
{
struct dm_config_node *cn, *last;
cn = cft->root;
last = cn;
while (cn->sib) {
last = cn->sib;
cn = last;
}
cn = dm_config_create_node(cft, node_name);
if (!cn)
return NULL;
cn->v = NULL;
cn->sib = NULL;
cn->parent = cft->root;
last->sib = cn;
return cn;
}
static struct dm_config_node *make_pv_node(lvmetad_state *s, const char *pvid,
struct dm_config_tree *cft,
struct dm_config_node *parent,
@@ -304,6 +429,9 @@ static response pv_list(lvmetad_state *s, request r)
cn = make_pv_node(s, id, res.cft, cn_pvs, cn);
}
if (s->flags & GLFL_INVALID)
add_last_node(res.cft, "global_invalid");
unlock_pvid_to_pvmeta(s);
return res;
@@ -348,6 +476,9 @@ static response pv_lookup(lvmetad_state *s, request r)
pv->key = "physical_volume";
unlock_pvid_to_pvmeta(s);
if (s->flags & GLFL_INVALID)
add_last_node(res.cft, "global_invalid");
return res;
}
@@ -416,14 +547,87 @@ static response vg_list(lvmetad_state *s, request r)
}
unlock_vgid_to_metadata(s);
if (s->flags & GLFL_INVALID)
add_last_node(res.cft, "global_invalid");
bad:
return res;
}
static void mark_outdated_pv(lvmetad_state *s, const char *vgid, const char *pvid)
{
struct dm_config_tree *pvmeta, *outdated_pvs;
struct dm_config_node *list, *cft_vgid;
struct dm_config_value *v;
lock_pvid_to_pvmeta(s);
pvmeta = dm_hash_lookup(s->pvid_to_pvmeta, pvid);
unlock_pvid_to_pvmeta(s);
/* if the MDA exists and is used, it will have ignore=0 set */
if (!pvmeta ||
(dm_config_find_int64(pvmeta->root, "pvmeta/mda0/ignore", 1) &&
dm_config_find_int64(pvmeta->root, "pvmeta/mda1/ignore", 1)))
return;
WARN(s, "PV %s has outdated metadata", pvid);
outdated_pvs = dm_hash_lookup(s->vgid_to_outdated_pvs, vgid);
if (!outdated_pvs) {
if (!(outdated_pvs = dm_config_from_string("outdated_pvs/pv_list = []")) ||
!(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))
abort();
DEBUGLOG(s, "created outdated_pvs list for VG %s", vgid);
}
list = dm_config_find_node(outdated_pvs->root, "outdated_pvs/pv_list");
v = list->v;
while (v) {
if (v->type != DM_CFG_EMPTY_ARRAY && !strcmp(v->v.str, pvid))
return;
v = v->next;
}
if (!(v = dm_config_create_value(outdated_pvs)))
abort();
v->type = DM_CFG_STRING;
v->v.str = dm_pool_strdup(outdated_pvs->mem, pvid);
v->next = list->v;
list->v = v;
}
static void chain_outdated_pvs(lvmetad_state *s, const char *vgid, struct dm_config_tree *metadata_cft, struct dm_config_node *metadata)
{
struct dm_config_tree *cft = dm_hash_lookup(s->vgid_to_outdated_pvs, vgid), *pvmeta;
struct dm_config_node *pv, *res, *out_pvs = cft ? dm_config_find_node(cft->root, "outdated_pvs/pv_list") : NULL;
struct dm_config_value *pvs_v = out_pvs ? out_pvs->v : NULL;
if (!pvs_v)
return;
if (!(res = make_config_node(metadata_cft, "outdated_pvs", metadata_cft->root, 0)))
return; /* oops */
res->sib = metadata->child;
metadata->child = res;
for (; pvs_v && pvs_v->type != DM_CFG_EMPTY_ARRAY; pvs_v = pvs_v->next) {
pvmeta = dm_hash_lookup(s->pvid_to_pvmeta, pvs_v->v.str);
if (!pvmeta) {
WARN(s, "metadata for PV %s not found", pvs_v->v.str);
continue;
}
if (!(pv = dm_config_clone_node(metadata_cft, pvmeta->root, 0)))
continue;
pv->key = dm_config_find_str(pv, "pvmeta/id", NULL);
pv->sib = res->child;
res->child = pv;
}
}
static response vg_lookup(lvmetad_state *s, request r)
{
struct dm_config_tree *cft;
struct dm_config_node *metadata, *n;
struct vg_info *info;
response res = { 0 };
const char *uuid = daemon_request_str(r, "uuid", NULL);
@@ -486,6 +690,17 @@ static response vg_lookup(lvmetad_state *s, request r)
unlock_vg(s, uuid);
update_pv_status(s, res.cft, n, 1); /* FIXME report errors */
chain_outdated_pvs(s, uuid, res.cft, n);
if (s->flags & GLFL_INVALID)
add_last_node(res.cft, "global_invalid");
info = dm_hash_lookup(s->vgid_to_info, uuid);
if (info && (info->flags & VGFL_INVALID)) {
n = add_last_node(res.cft, "vg_invalid");
if (!n)
goto bad;
}
return res;
bad:
@@ -493,65 +708,13 @@ bad:
return reply_fail("out of memory");
}
/* Test if the doubles are close enough to be considered equal */
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 r = 0;
if (a->type > b->type)
return 1;
if (a->type < b->type)
return -1;
switch (a->type) {
case DM_CFG_STRING: r = strcmp(a->v.str, b->v.str); break;
case DM_CFG_FLOAT: r = close_enough(a->v.f, b->v.f) ? 0 : (a->v.f > b->v.f) ? 1 : -1; break;
case DM_CFG_INT: r = (a->v.i == b->v.i) ? 0 : (a->v.i > b->v.i) ? 1 : -1; break;
case DM_CFG_EMPTY_ARRAY: return 0;
}
if (r == 0 && a->next && b->next)
r = compare_value(a->next, b->next);
return r;
}
static int compare_config(struct dm_config_node *a, struct dm_config_node *b)
{
int result = 0;
if (a->v && b->v)
result = compare_value(a->v, b->v);
if (a->v && !b->v)
result = 1;
if (!a->v && b->v)
result = -1;
if (a->child && b->child)
result = compare_config(a->child, b->child);
if (result) {
// DEBUGLOG("config inequality at %s / %s", a->key, b->key);
return result;
}
if (a->sib && b->sib)
result = compare_config(a->sib, b->sib);
if (a->sib && !b->sib)
result = 1;
if (!a->sib && b->sib)
result = -1;
return result;
}
static int vg_remove_if_missing(lvmetad_state *s, const char *vgid, int update_pvids);
enum update_pvid_mode { UPDATE_ONLY, REMOVE_EMPTY, MARK_OUTDATED };
/* You need to be holding the pvid_to_vgid lock already to call this. */
static int update_pvid_to_vgid(lvmetad_state *s, struct dm_config_tree *vg,
const char *vgid, int nuke_empty)
const char *vgid, int mode)
{
struct dm_config_node *pv;
struct dm_hash_table *to_check;
@@ -571,11 +734,14 @@ static int update_pvid_to_vgid(lvmetad_state *s, struct dm_config_tree *vg,
if (!(pvid = dm_config_find_str(pv->child, "id", NULL)))
continue;
if (nuke_empty &&
if (mode == REMOVE_EMPTY &&
(vgid_old = dm_hash_lookup(s->pvid_to_vgid, pvid)) &&
!dm_hash_insert(to_check, vgid_old, (void*) 1))
goto out;
if (mode == MARK_OUTDATED)
mark_outdated_pv(s, vgid, pvid);
if (!dm_hash_insert(s->pvid_to_vgid, pvid, (void*) vgid))
goto out;
@@ -599,10 +765,11 @@ static int update_pvid_to_vgid(lvmetad_state *s, struct dm_config_tree *vg,
/* A pvid map lock needs to be held if update_pvids = 1. */
static int remove_metadata(lvmetad_state *s, const char *vgid, int update_pvids)
{
struct dm_config_tree *old;
struct dm_config_tree *old, *outdated_pvs;
const char *oldname;
lock_vgid_to_metadata(s);
old = dm_hash_lookup(s->vgid_to_metadata, vgid);
outdated_pvs = dm_hash_lookup(s->vgid_to_outdated_pvs, vgid);
oldname = dm_hash_lookup(s->vgid_to_vgname, vgid);
if (!old) {
@@ -616,12 +783,15 @@ static int remove_metadata(lvmetad_state *s, const char *vgid, int update_pvids)
dm_hash_remove(s->vgid_to_metadata, vgid);
dm_hash_remove(s->vgid_to_vgname, vgid);
dm_hash_remove(s->vgname_to_vgid, oldname);
dm_hash_remove(s->vgid_to_outdated_pvs, vgid);
unlock_vgid_to_metadata(s);
if (update_pvids)
/* FIXME: What should happen when update fails */
update_pvid_to_vgid(s, old, "#orphan", 0);
dm_config_destroy(old);
if (outdated_pvs)
dm_config_destroy(outdated_pvs);
return 1;
}
@@ -665,7 +835,7 @@ static int vg_remove_if_missing(lvmetad_state *s, const char *vgid, int update_p
* this function, so they can be safely destroyed after update_metadata returns
* (anything that might have been retained is copied). */
static int update_metadata(lvmetad_state *s, const char *name, const char *_vgid,
struct dm_config_node *metadata, int64_t *oldseq)
struct dm_config_node *metadata, int64_t *oldseq, const char *pvid)
{
struct dm_config_tree *cft = NULL;
struct dm_config_tree *old;
@@ -714,6 +884,10 @@ static int update_metadata(lvmetad_state *s, const char *name, const char *_vgid
if (seq < haveseq) {
DEBUGLOG(s, "Refusing to update metadata for %s (at %d) to %d", _vgid, haveseq, seq);
if (pvid)
mark_outdated_pv(s, dm_config_find_str(old->root, "metadata/id", NULL), pvid);
/* TODO: notify the client that their metadata is out of date? */
retval = 1;
goto out;
@@ -736,6 +910,8 @@ static int update_metadata(lvmetad_state *s, const char *name, const char *_vgid
if (haveseq >= 0 && haveseq < seq) {
INFO(s, "Updating metadata for %s at %d to %d", _vgid, haveseq, seq);
if (oldseq)
update_pvid_to_vgid(s, old, vgid, MARK_OUTDATED);
/* temporarily orphan all of our PVs */
update_pvid_to_vgid(s, old, "#orphan", 0);
}
@@ -823,7 +999,8 @@ static response pv_gone(lvmetad_state *s, request r)
DEBUGLOG(s, "pv_gone (updated): %s / %" PRIu64, pvid, device);
pvmeta = dm_hash_lookup(s->pvid_to_pvmeta, pvid);
if (!(pvmeta = dm_hash_lookup(s->pvid_to_pvmeta, pvid)))
return reply_unknown("PVID does not exist");
vgid = dm_hash_lookup(s->pvid_to_vgid, pvid);
dm_hash_remove_binary(s->device_to_pvid, &device, sizeof(device));
@@ -845,9 +1022,6 @@ static response pv_gone(lvmetad_state *s, request r)
dm_free(vgid);
}
if (!pvmeta)
return reply_unknown("PVID does not exist");
if (!alt_device)
dm_config_destroy(pvmeta);
@@ -992,7 +1166,7 @@ out_of_mem:
if (daemon_request_int(r, "metadata/seqno", -1) < 0)
return reply_fail("need VG seqno");
if (!update_metadata(s, vgname, vgid, metadata, &seqno_old))
if (!update_metadata(s, vgname, vgid, metadata, &seqno_old, pvid))
return reply_fail("metadata update failed");
changed |= (seqno_old != dm_config_find_int(metadata, "metadata/seqno", -1));
} else {
@@ -1040,6 +1214,39 @@ out_of_mem:
NULL);
}
static response vg_clear_outdated_pvs(lvmetad_state *s, request r)
{
struct dm_config_tree *outdated_pvs;
const char *vgid = daemon_request_str(r, "vgid", NULL);
if (!vgid)
return reply_fail("need VG UUID");
if ((outdated_pvs = dm_hash_lookup(s->vgid_to_outdated_pvs, vgid))) {
dm_config_destroy(outdated_pvs);
dm_hash_remove(s->vgid_to_outdated_pvs, vgid);
}
return daemon_reply_simple("OK", NULL);
}
static void vg_info_update(lvmetad_state *s, const char *uuid,
struct dm_config_node *metadata)
{
struct vg_info *info;
int64_t cache_version;
cache_version = dm_config_find_int64(metadata, "metadata/seqno", -1);
if (cache_version == -1)
return;
info = (struct vg_info *) dm_hash_lookup(s->vgid_to_info, uuid);
if (!info)
return;
if (cache_version >= info->external_version)
info->flags &= ~VGFL_INVALID;
}
static response vg_update(lvmetad_state *s, request r)
{
struct dm_config_node *metadata = dm_config_find_node(r.cft->root, "metadata");
@@ -1055,8 +1262,10 @@ static response vg_update(lvmetad_state *s, request r)
/* TODO defer metadata update here; add a separate vg_commit
* call; if client does not commit, die */
if (!update_metadata(s, vgname, vgid, metadata, NULL))
if (!update_metadata(s, vgname, vgid, metadata, NULL, NULL))
return reply_fail("metadata update failed");
vg_info_update(s, vgid, metadata);
}
return daemon_reply_simple("OK", NULL);
}
@@ -1077,6 +1286,71 @@ static response vg_remove(lvmetad_state *s, request r)
return daemon_reply_simple("OK", NULL);
}
static response set_global_info(lvmetad_state *s, request r)
{
const int global_invalid = daemon_request_int(r, "global_invalid", -1);
if (global_invalid == 1)
s->flags |= GLFL_INVALID;
else if (global_invalid == 0)
s->flags &= ~GLFL_INVALID;
return daemon_reply_simple("OK", NULL);
}
static response get_global_info(lvmetad_state *s, request r)
{
return daemon_reply_simple("OK", "global_invalid = %d",
(s->flags & GLFL_INVALID) ? 1 : 0,
NULL);
}
static response set_vg_info(lvmetad_state *s, request r)
{
struct dm_config_tree *vg;
struct vg_info *info;
const char *uuid = daemon_request_str(r, "uuid", NULL);
const int64_t new_version = daemon_request_int(r, "version", -1);
int64_t cache_version;
if (!uuid)
goto out;
if (new_version == -1)
goto out;
vg = dm_hash_lookup(s->vgid_to_metadata, uuid);
if (!vg)
goto out;
if (!new_version)
goto inval;
cache_version = dm_config_find_int64(vg->root, "metadata/seqno", -1);
if (cache_version != -1 && new_version != -1 && cache_version >= new_version)
goto out;
inval:
info = dm_hash_lookup(s->vgid_to_info, uuid);
if (!info) {
info = malloc(sizeof(struct vg_info));
if (!info)
goto bad;
memset(info, 0, sizeof(struct vg_info));
if (!dm_hash_insert(s->vgid_to_info, uuid, (void*)info))
goto bad;
}
info->external_version = new_version;
info->flags |= VGFL_INVALID;
out:
return daemon_reply_simple("OK", NULL);
bad:
return reply_fail("out of memory");
}
static void _dump_cft(struct buffer *buf, struct dm_hash_table *ht, const char *key_addr)
{
struct dm_hash_node *n;
@@ -1114,6 +1388,52 @@ static void _dump_pairs(struct buffer *buf, struct dm_hash_table *ht, const char
buffer_append(buf, "}\n");
}
static void _dump_info_version(struct buffer *buf, struct dm_hash_table *ht, const char *name, int int_key)
{
char *append;
struct dm_hash_node *n = dm_hash_get_first(ht);
struct vg_info *info;
buffer_append(buf, name);
buffer_append(buf, " {\n");
while (n) {
const char *key = dm_hash_get_key(ht, n);
info = dm_hash_get_data(ht, n);
buffer_append(buf, " ");
(void) dm_asprintf(&append, "%s = %lld", key, (long long)info->external_version);
if (append)
buffer_append(buf, append);
buffer_append(buf, "\n");
dm_free(append);
n = dm_hash_get_next(ht, n);
}
buffer_append(buf, "}\n");
}
static void _dump_info_flags(struct buffer *buf, struct dm_hash_table *ht, const char *name, int int_key)
{
char *append;
struct dm_hash_node *n = dm_hash_get_first(ht);
struct vg_info *info;
buffer_append(buf, name);
buffer_append(buf, " {\n");
while (n) {
const char *key = dm_hash_get_key(ht, n);
info = dm_hash_get_data(ht, n);
buffer_append(buf, " ");
(void) dm_asprintf(&append, "%s = %llx", key, (long long)info->flags);
if (append)
buffer_append(buf, append);
buffer_append(buf, "\n");
dm_free(append);
n = dm_hash_get_next(ht, n);
}
buffer_append(buf, "}\n");
}
static response dump(lvmetad_state *s)
{
response res = { 0 };
@@ -1136,6 +1456,9 @@ static response dump(lvmetad_state *s)
buffer_append(b, "\n# VGID to VGNAME mapping\n\n");
_dump_pairs(b, s->vgid_to_vgname, "vgid_to_vgname", 0);
buffer_append(b, "\n# VGID to outdated PVs mapping\n\n");
_dump_cft(b, s->vgid_to_outdated_pvs, "outdated_pvs/vgid");
buffer_append(b, "\n# VGNAME to VGID mapping\n\n");
_dump_pairs(b, s->vgname_to_vgid, "vgname_to_vgid", 0);
@@ -1145,6 +1468,12 @@ static response dump(lvmetad_state *s)
buffer_append(b, "\n# DEVICE to PVID mapping\n\n");
_dump_pairs(b, s->device_to_pvid, "device_to_pvid", 1);
buffer_append(b, "\n# VGID to INFO version mapping\n\n");
_dump_info_version(b, s->vgid_to_info, "vgid_to_info", 0);
buffer_append(b, "\n# VGID to INFO flags mapping\n\n");
_dump_info_flags(b, s->vgid_to_info, "vgid_to_info", 0);
unlock_pvid_to_vgid(s);
unlock_pvid_to_pvmeta(s);
unlock_vgid_to_metadata(s);
@@ -1166,7 +1495,7 @@ static response handler(daemon_state s, client_handle h, request r)
return daemon_reply_simple("OK", NULL);
}
if (strcmp(token, state->token) && strcmp(rq, "dump")) {
if (strcmp(token, state->token) && strcmp(rq, "dump") && strcmp(token, "skip")) {
pthread_mutex_unlock(&state->token_lock);
return daemon_reply_simple("token_mismatch",
"expected = %s", state->token,
@@ -1195,6 +1524,9 @@ static response handler(daemon_state s, client_handle h, request r)
if (!strcmp(rq, "vg_update"))
return vg_update(state, r);
if (!strcmp(rq, "vg_clear_outdated_pvs"))
return vg_clear_outdated_pvs(state, r);
if (!strcmp(rq, "vg_remove"))
return vg_remove(state, r);
@@ -1207,6 +1539,15 @@ static response handler(daemon_state s, client_handle h, request r)
if (!strcmp(rq, "vg_list"))
return vg_list(state, r);
if (!strcmp(rq, "set_global_info"))
return set_global_info(state, r);
if (!strcmp(rq, "get_global_info"))
return get_global_info(state, r);
if (!strcmp(rq, "set_vg_info"))
return set_vg_info(state, r);
if (!strcmp(rq, "dump"))
return dump(state);

View File

@@ -1,3 +1,18 @@
/*
* Copyright (C) 2011-2014 Red Hat, Inc.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "tool.h"
#include "lvmetad-client.h"
#include "label.h"
#include "lvmcache.h"
@@ -109,7 +124,7 @@ int main(int argc, char **argv) {
if (argc > 1) {
int i;
struct cmd_context *cmd = create_toolcontext(0, NULL, 0, 0);
struct cmd_context *cmd = create_toolcontext(0, NULL, 0, 0, 1, 1);
for (i = 1; i < argc; ++i) {
const char *uuid = NULL;
scan(h, argv[i]);

2
daemons/lvmlockd/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
lvmlockctl
lvmlockd

View File

@@ -0,0 +1,66 @@
#
# Copyright (C) 2014-2015 Red Hat, Inc.
#
# 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
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
SOURCES = lvmlockd-core.c
ifeq ("@BUILD_LOCKDSANLOCK@", "yes")
SOURCES += lvmlockd-sanlock.c
endif
ifeq ("@BUILD_LOCKDDLM@", "yes")
SOURCES += lvmlockd-dlm.c
endif
TARGETS = lvmlockd lvmlockctl
.PHONY: install_lvmlockd
include $(top_builddir)/make.tmpl
INCLUDES += -I$(top_srcdir)/libdaemon/server
LVMLIBS = -ldaemonserver $(LVMINTERNAL_LIBS) -ldevmapper
LIBS += $(PTHREAD_LIBS)
ifeq ("@BUILD_LOCKDSANLOCK@", "yes")
LIBS += -lsanlock_client
endif
ifeq ("@BUILD_LOCKDDLM@", "yes")
LIBS += -ldlm_lt
endif
LDFLAGS += -L$(top_builddir)/libdaemon/server
CLDFLAGS += -L$(top_builddir)/libdaemon/server
lvmlockd: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
$(top_builddir)/libdaemon/server/libdaemonserver.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LVMLIBS) $(LIBS)
lvmlockctl: lvmlockctl.o $(top_builddir)/libdaemon/client/libdaemonclient.a \
$(top_builddir)/libdaemon/server/libdaemonserver.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmlockctl.o $(LVMLIBS)
install_lvmlockd: lvmlockd
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
install_lvmlockctl: lvmlockctl
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
install_lvm2: install_lvmlockd install_lvmlockctl
install: install_lvm2

View File

@@ -0,0 +1,745 @@
/*
* Copyright (C) 2014-2015 Red Hat, Inc.
*
* 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.
*/
#include "tool.h"
#include "lvmlockd-client.h"
#include <stddef.h>
#include <getopt.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <syslog.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/un.h>
static int quit = 0;
static int info = 0;
static int dump = 0;
static int wait_opt = 0;
static int force_opt = 0;
static int kill_vg = 0;
static int drop_vg = 0;
static int gl_enable = 0;
static int gl_disable = 0;
static int stop_lockspaces = 0;
static char *arg_vg_name = NULL;
#define DUMP_SOCKET_NAME "lvmlockd-dump.sock"
#define DUMP_BUF_SIZE (1024 * 1024)
static char dump_buf[DUMP_BUF_SIZE+1];
static int dump_len;
static struct sockaddr_un dump_addr;
static socklen_t dump_addrlen;
daemon_handle _lvmlockd;
#define log_error(fmt, args...) \
do { \
printf(fmt "\n", ##args); \
} while (0)
#define MAX_LINE 512
/* copied from lvmlockd-internal.h */
#define MAX_NAME 64
#define MAX_ARGS 64
/*
* lvmlockd dumps the client info before the lockspaces,
* so we can look up client info when printing lockspace info.
*/
#define MAX_CLIENTS 100
struct client_info {
uint32_t client_id;
int pid;
char name[MAX_NAME+1];
};
static struct client_info clients[MAX_CLIENTS];
static int num_clients;
static void save_client_info(char *line)
{
uint32_t pid = 0;
int fd = 0;
int pi = 0;
uint32_t client_id = 0;
char name[MAX_NAME+1] = { 0 };
sscanf(line, "info=client pid=%u fd=%d pi=%d id=%u name=%s",
&pid, &fd, &pi, &client_id, name);
clients[num_clients].client_id = client_id;
clients[num_clients].pid = pid;
strcpy(clients[num_clients].name, name);
num_clients++;
}
static void find_client_info(uint32_t client_id, uint32_t *pid, char *cl_name)
{
int i;
for (i = 0; i < num_clients; i++) {
if (clients[i].client_id == client_id) {
*pid = clients[i].pid;
strcpy(cl_name, clients[i].name);
return;
}
}
}
static int first_ls = 1;
static void format_info_ls(char *line)
{
char ls_name[MAX_NAME+1] = { 0 };
char vg_name[MAX_NAME+1] = { 0 };
char vg_uuid[MAX_NAME+1] = { 0 };
char vg_sysid[MAX_NAME+1] = { 0 };
char lock_args[MAX_ARGS+1] = { 0 };
char lock_type[MAX_NAME+1] = { 0 };
sscanf(line, "info=ls ls_name=%s vg_name=%s vg_uuid=%s vg_sysid=%s vg_args=%s lm_type=%s",
ls_name, vg_name, vg_uuid, vg_sysid, lock_args, lock_type);
if (!first_ls)
printf("\n");
first_ls = 0;
printf("VG %s lock_type=%s %s\n", vg_name, lock_type, vg_uuid);
printf("LS %s %s\n", lock_type, ls_name);
}
static void format_info_ls_action(char *line)
{
uint32_t client_id = 0;
char flags[MAX_NAME+1] = { 0 };
char version[MAX_NAME+1] = { 0 };
char op[MAX_NAME+1] = { 0 };
uint32_t pid = 0;
char cl_name[MAX_NAME+1] = { 0 };
sscanf(line, "info=ls_action client_id=%u %s %s op=%s",
&client_id, flags, version, op);
find_client_info(client_id, &pid, cl_name);
printf("OP %s pid %u (%s)\n", op, pid, cl_name);
}
static void format_info_r(char *line, char *r_name_out, char *r_type_out)
{
char r_name[MAX_NAME+1] = { 0 };
char r_type[4] = { 0 };
char mode[4] = { 0 };
char sh_count[MAX_NAME+1] = { 0 };
uint32_t ver = 0;
sscanf(line, "info=r name=%s type=%s mode=%s %s version=%u",
r_name, r_type, mode, sh_count, &ver);
/* when mode is not un, wait and print each lk line */
if (strcmp(mode, "un")) {
strcpy(r_name_out, r_name);
strcpy(r_type_out, r_type);
return;
}
/* when mode is un, there will be no lk lines, so print now */
if (!strcmp(r_type, "gl")) {
printf("LK GL un ver %u\n", ver);
} else if (!strcmp(r_type, "vg")) {
printf("LK VG un ver %u\n", ver);
} else if (!strcmp(r_type, "lv")) {
printf("LK LV un %s\n", r_name);
}
}
static void format_info_lk(char *line, char *r_name, char *r_type)
{
char mode[4] = { 0 };
uint32_t ver = 0;
char flags[MAX_NAME+1] = { 0 };
uint32_t client_id = 0;
uint32_t pid = 0;
char cl_name[MAX_NAME+1] = { 0 };
if (!r_name[0] || !r_type[0]) {
printf("format_info_lk error r_name %s r_type %s\n", r_name, r_type);
printf("%s\n", line);
return;
}
sscanf(line, "info=lk mode=%s version=%u %s client_id=%u",
mode, &ver, flags, &client_id);
find_client_info(client_id, &pid, cl_name);
if (!strcmp(r_type, "gl")) {
printf("LK GL %s ver %u pid %u (%s)\n", mode, ver, pid, cl_name);
} else if (!strcmp(r_type, "vg")) {
printf("LK VG %s ver %u pid %u (%s)\n", mode, ver, pid, cl_name);
} else if (!strcmp(r_type, "lv")) {
printf("LK LV %s %s\n", mode, r_name);
}
}
static void format_info_r_action(char *line, char *r_name, char *r_type)
{
uint32_t client_id = 0;
char flags[MAX_NAME+1] = { 0 };
char version[MAX_NAME+1] = { 0 };
char op[MAX_NAME+1] = { 0 };
char rt[4] = { 0 };
char mode[4] = { 0 };
char lm[MAX_NAME+1] = { 0 };
char result[MAX_NAME+1] = { 0 };
char lm_rv[MAX_NAME+1] = { 0 };
uint32_t pid = 0;
char cl_name[MAX_NAME+1] = { 0 };
if (!r_name[0] || !r_type[0]) {
printf("format_info_r_action error r_name %s r_type %s\n", r_name, r_type);
printf("%s\n", line);
return;
}
sscanf(line, "info=r_action client_id=%u %s %s op=%s rt=%s mode=%s %s %s %s",
&client_id, flags, version, op, rt, mode, lm, result, lm_rv);
find_client_info(client_id, &pid, cl_name);
if (strcmp(op, "lock")) {
printf("OP %s pid %u (%s)", op, pid, cl_name);
return;
}
if (!strcmp(r_type, "gl")) {
printf("LW GL %s ver %u pid %u (%s)\n", mode, 0, pid, cl_name);
} else if (!strcmp(r_type, "vg")) {
printf("LW VG %s ver %u pid %u (%s)\n", mode, 0, pid, cl_name);
} else if (!strcmp(r_type, "lv")) {
printf("LW LV %s %s\n", mode, r_name);
}
}
static void format_info_line(char *line, char *r_name, char *r_type)
{
if (!strncmp(line, "info=structs ", strlen("info=structs "))) {
/* only print this in the raw info dump */
} else if (!strncmp(line, "info=client ", strlen("info=client "))) {
save_client_info(line);
} else if (!strncmp(line, "info=ls ", strlen("info=ls "))) {
format_info_ls(line);
} else if (!strncmp(line, "info=ls_action ", strlen("info=ls_action "))) {
format_info_ls_action(line);
} else if (!strncmp(line, "info=r ", strlen("info=r "))) {
/*
* r_name/r_type are reset when a new resource is found.
* They are reused for the lock and action lines that
* follow a resource line.
*/
memset(r_name, 0, MAX_NAME+1);
memset(r_type, 0, MAX_NAME+1);
format_info_r(line, r_name, r_type);
} else if (!strncmp(line, "info=lk ", strlen("info=lk "))) {
/* will use info from previous r */
format_info_lk(line, r_name, r_type);
} else if (!strncmp(line, "info=r_action ", strlen("info=r_action "))) {
/* will use info from previous r */
format_info_r_action(line, r_name, r_type);
} else {
printf("UN %s\n", line);
}
}
static void format_info(void)
{
char line[MAX_LINE];
char r_name[MAX_NAME+1];
char r_type[MAX_NAME+1];
int i, j;
j = 0;
memset(line, 0, sizeof(line));
for (i = 0; i < dump_len; i++) {
line[j++] = dump_buf[i];
if ((line[j-1] == '\n') || (line[j-1] == '\0')) {
format_info_line(line, r_name, r_type);
j = 0;
memset(line, 0, sizeof(line));
}
}
}
static daemon_reply _lvmlockd_send(const char *req_name, ...)
{
va_list ap;
daemon_reply repl;
daemon_request req;
req = daemon_request_make(req_name);
va_start(ap, req_name);
daemon_request_extend_v(req, ap);
va_end(ap);
repl = daemon_send(_lvmlockd, req);
daemon_request_destroy(req);
return repl;
}
/* See the same in lib/locking/lvmlockd.c */
#define NO_LOCKD_RESULT -1000
static int _lvmlockd_result(daemon_reply reply, int *result)
{
int reply_result;
if (reply.error) {
log_error("lvmlockd_result reply error %d", reply.error);
return 0;
}
if (strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
log_error("lvmlockd_result bad response");
return 0;
}
reply_result = daemon_reply_int(reply, "op_result", NO_LOCKD_RESULT);
if (reply_result == -1000) {
log_error("lvmlockd_result no op_result");
return 0;
}
*result = reply_result;
return 1;
}
static int do_quit(void)
{
daemon_reply reply;
int rv = 0;
reply = daemon_send_simple(_lvmlockd, "quit", NULL);
if (reply.error) {
log_error("reply error %d", reply.error);
rv = reply.error;
}
daemon_reply_destroy(reply);
return rv;
}
static int setup_dump_socket(void)
{
int s, rv;
s = socket(AF_LOCAL, SOCK_DGRAM, 0);
if (s < 0)
return s;
memset(&dump_addr, 0, sizeof(dump_addr));
dump_addr.sun_family = AF_LOCAL;
strcpy(&dump_addr.sun_path[1], DUMP_SOCKET_NAME);
dump_addrlen = sizeof(sa_family_t) + strlen(dump_addr.sun_path+1) + 1;
rv = bind(s, (struct sockaddr *) &dump_addr, dump_addrlen);
if (rv < 0) {
if (!close(s))
log_error("failed to close dump socket");
return rv;
}
return s;
}
static int do_dump(const char *req_name)
{
daemon_reply reply;
int result;
int fd, rv = 0;
fd = setup_dump_socket();
if (fd < 0) {
log_error("socket error %d", fd);
return fd;
}
reply = daemon_send_simple(_lvmlockd, req_name, NULL);
if (reply.error) {
log_error("reply error %d", reply.error);
rv = reply.error;
goto out;
}
result = daemon_reply_int(reply, "result", 0);
dump_len = daemon_reply_int(reply, "dump_len", 0);
daemon_reply_destroy(reply);
if (result < 0) {
rv = result;
log_error("result %d", result);
}
if (!dump_len)
goto out;
memset(dump_buf, 0, sizeof(dump_buf));
rv = recvfrom(fd, dump_buf, dump_len, MSG_WAITALL,
(struct sockaddr *)&dump_addr, &dump_addrlen);
if (rv < 0) {
log_error("recvfrom error %d %d", rv, errno);
rv = -errno;
goto out;
}
rv = 0;
if ((info && dump) || !strcmp(req_name, "dump"))
printf("%s\n", dump_buf);
else
format_info();
out:
if (close(fd))
log_error("failed to close dump socket %d", fd);
return rv;
}
static int do_able(const char *req_name)
{
daemon_reply reply;
int result;
int rv;
reply = _lvmlockd_send(req_name,
"cmd = %s", "lvmlockctl",
"pid = %d", getpid(),
"vg_name = %s", arg_vg_name,
NULL);
if (!_lvmlockd_result(reply, &result)) {
log_error("lvmlockd result %d", result);
rv = result;
} else {
rv = 0;
}
daemon_reply_destroy(reply);
return rv;
}
static int do_stop_lockspaces(void)
{
daemon_reply reply;
char opts[32];
int result;
int rv;
memset(opts, 0, sizeof(opts));
if (wait_opt)
strcat(opts, "wait ");
if (force_opt)
strcat(opts, "force ");
reply = _lvmlockd_send("stop_all",
"cmd = %s", "lvmlockctl",
"pid = %d", getpid(),
"opts = %s", opts[0] ? opts : "none",
NULL);
if (!_lvmlockd_result(reply, &result)) {
log_error("lvmlockd result %d", result);
rv = result;
} else {
rv = 0;
}
daemon_reply_destroy(reply);
return rv;
}
static int do_kill(void)
{
daemon_reply reply;
int result;
int rv;
syslog(LOG_EMERG, "Lost access to sanlock lease storage in VG %s.", arg_vg_name);
/* These two lines explain the manual alternative to the FIXME below. */
syslog(LOG_EMERG, "Immediately deactivate LVs in VG %s.", arg_vg_name);
syslog(LOG_EMERG, "Once VG is unused, run lvmlockctl --drop %s.", arg_vg_name);
/*
* It may not be strictly necessary to notify lvmlockd of the kill, but
* lvmlockd can use this information to avoid attempting any new lock
* requests in the VG (which would fail anyway), and can return an
* error indicating that the VG has been killed.
*/
reply = _lvmlockd_send("kill_vg",
"cmd = %s", "lvmlockctl",
"pid = %d", getpid(),
"vg_name = %s", arg_vg_name,
NULL);
if (!_lvmlockd_result(reply, &result)) {
log_error("lvmlockd result %d", result);
rv = result;
} else {
rv = 0;
}
daemon_reply_destroy(reply);
/*
* FIXME: here is where we should implement a strong form of
* blkdeactivate, and if it completes successfully, automatically call
* do_drop() afterward. (The drop step may not always be necessary
* if the lvm commands run while shutting things down release all the
* leases.)
*
* run_strong_blkdeactivate();
* do_drop();
*/
return rv;
}
static int do_drop(void)
{
daemon_reply reply;
int result;
int rv;
syslog(LOG_WARNING, "Dropping locks for VG %s.", arg_vg_name);
/*
* Check for misuse by looking for any active LVs in the VG
* and refusing this operation if found? One possible way
* to kill LVs (e.g. if fs cannot be unmounted) is to suspend
* them, or replace them with the error target. In that
* case the LV will still appear to be active, but it is
* safe to release the lock.
*/
reply = _lvmlockd_send("drop_vg",
"cmd = %s", "lvmlockctl",
"pid = %d", getpid(),
"vg_name = %s", arg_vg_name,
NULL);
if (!_lvmlockd_result(reply, &result)) {
log_error("lvmlockd result %d", result);
rv = result;
} else {
rv = 0;
}
daemon_reply_destroy(reply);
return rv;
}
static void print_usage(void)
{
printf("lvmlockctl options\n");
printf("Options:\n");
printf("--help | -h\n");
printf(" Show this help information.\n");
printf("--quit | -q\n");
printf(" Tell lvmlockd to quit.\n");
printf("--info | -i\n");
printf(" Print lock state information from lvmlockd.\n");
printf("--dump | -d\n");
printf(" Print log buffer from lvmlockd.\n");
printf("--wait | -w 0|1\n");
printf(" Wait option for other commands.\n");
printf("--force | -f 0|1>\n");
printf(" Force option for other commands.\n");
printf("--kill | -k <vg_name>\n");
printf(" Kill access to the vg when sanlock cannot renew lease.\n");
printf("--drop | -r <vg_name>\n");
printf(" Clear locks for the vg after it has been killed and is no longer used.\n");
printf("--gl-enable <vg_name>\n");
printf(" Tell lvmlockd to enable the global lock in a sanlock vg.\n");
printf("--gl-disable <vg_name>\n");
printf(" Tell lvmlockd to disable the global lock in a sanlock vg.\n");
printf("--stop-lockspaces | -S\n");
printf(" Stop all lockspaces.\n");
}
static int read_options(int argc, char *argv[])
{
int option_index = 0;
int c;
static struct option long_options[] = {
{"help", no_argument, 0, 'h' },
{"quit", no_argument, 0, 'q' },
{"info", no_argument, 0, 'i' },
{"dump", no_argument, 0, 'd' },
{"wait", required_argument, 0, 'w' },
{"force", required_argument, 0, 'f' },
{"kill", required_argument, 0, 'k' },
{"drop", required_argument, 0, 'r' },
{"gl-enable", required_argument, 0, 'E' },
{"gl-disable", required_argument, 0, 'D' },
{"stop-lockspaces", no_argument, 0, 'S' },
{0, 0, 0, 0 }
};
if (argc == 1) {
print_usage();
exit(0);
}
while (1) {
c = getopt_long(argc, argv, "hqidE:D:w:k:r:S", long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 'h':
/* --help */
print_usage();
exit(0);
case 'q':
/* --quit */
quit = 1;
break;
case 'i':
/* --info */
info = 1;
break;
case 'd':
/* --dump */
dump = 1;
break;
case 'w':
wait_opt = atoi(optarg);
break;
case 'k':
kill_vg = 1;
arg_vg_name = strdup(optarg);
break;
case 'r':
drop_vg = 1;
arg_vg_name = strdup(optarg);
break;
case 'E':
gl_enable = 1;
arg_vg_name = strdup(optarg);
break;
case 'D':
gl_disable = 1;
arg_vg_name = strdup(optarg);
break;
case 'S':
stop_lockspaces = 1;
break;
default:
print_usage();
exit(1);
}
}
return 0;
}
int main(int argc, char **argv)
{
int rv = 0;
rv = read_options(argc, argv);
if (rv < 0)
return rv;
_lvmlockd = lvmlockd_open(NULL);
if (_lvmlockd.socket_fd < 0 || _lvmlockd.error) {
log_error("Cannot connect to lvmlockd.");
return -1;
}
if (quit) {
rv = do_quit();
goto out;
}
if (info) {
rv = do_dump("info");
goto out;
}
if (dump) {
rv = do_dump("dump");
goto out;
}
if (kill_vg) {
rv = do_kill();
goto out;
}
if (drop_vg) {
rv = do_drop();
goto out;
}
if (gl_enable) {
rv = do_able("enable_gl");
goto out;
}
if (gl_disable) {
rv = do_able("disable_gl");
goto out;
}
if (stop_lockspaces) {
rv = do_stop_lockspaces();
goto out;
}
out:
lvmlockd_close(_lvmlockd);
return rv;
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (C) 2014-2015 Red Hat, Inc.
*
* 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.
*/
#ifndef _LVM_LVMLOCKD_CLIENT_H
#define _LVM_LVMLOCKD_CLIENT_H
#include "daemon-client.h"
#define LVMLOCKD_SOCKET DEFAULT_RUN_DIR "/lvmlockd.socket"
/* Wrappers to open/close connection */
static inline daemon_handle lvmlockd_open(const char *sock)
{
daemon_info lvmlockd_info = {
.path = "lvmlockd",
.socket = sock ?: LVMLOCKD_SOCKET,
.protocol = "lvmlockd",
.protocol_version = 1,
.autostart = 0
};
return daemon_open(lvmlockd_info);
}
static inline void lvmlockd_close(daemon_handle h)
{
return daemon_close(h);
}
/*
* Errors returned as the lvmlockd result value.
*/
#define ENOLS 210 /* lockspace not found */
#define ESTARTING 211 /* lockspace is starting */
#define EARGS 212
#define EHOSTID 213
#define EMANAGER 214
#define EPREPARE 215
#define ELOCKD 216
#define EVGKILLED 217 /* sanlock lost access to leases and VG is killed. */
#define ELOCKIO 218 /* sanlock io errors during lock op, may be transient. */
#endif /* _LVM_LVMLOCKD_CLIENT_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,662 @@
/*
* Copyright (C) 2014-2015 Red Hat, Inc.
*
* 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.
*/
#define _XOPEN_SOURCE 500 /* pthread */
#define _ISOC99_SOURCE
#include "tool.h"
#include "daemon-server.h"
#include "daemon-log.h"
#include "xlate.h"
#include "lvmlockd-internal.h"
#include "lvmlockd-client.h"
/*
* Using synchronous _wait dlm apis so do not define _REENTRANT and
* link with non-threaded version of library, libdlm_lt.
*/
#include "libdlm.h"
#include <pthread.h>
#include <stddef.h>
#include <poll.h>
#include <errno.h>
#include <endian.h>
#include <fcntl.h>
#include <byteswap.h>
#include <syslog.h>
#include <dirent.h>
#include <sys/socket.h>
struct lm_dlm {
dlm_lshandle_t *dh;
};
struct rd_dlm {
struct dlm_lksb lksb;
struct val_blk *vb;
};
int lm_data_size_dlm(void)
{
return sizeof(struct rd_dlm);
}
/*
* lock_args format
*
* vg_lock_args format for dlm is
* vg_version_string:undefined:cluster_name
*
* lv_lock_args are not used for dlm
*
* version_string is MAJOR.MINOR.PATCH
* undefined may contain ":"
*/
#define VG_LOCK_ARGS_MAJOR 1
#define VG_LOCK_ARGS_MINOR 0
#define VG_LOCK_ARGS_PATCH 0
static int cluster_name_from_args(char *vg_args, char *clustername)
{
return last_string_from_args(vg_args, clustername);
}
static int check_args_version(char *vg_args)
{
unsigned int major = 0;
int rv;
rv = version_from_args(vg_args, &major, NULL, NULL);
if (rv < 0) {
log_error("check_args_version %s error %d", vg_args, rv);
return rv;
}
if (major > VG_LOCK_ARGS_MAJOR) {
log_error("check_args_version %s major %d %d", vg_args, major, VG_LOCK_ARGS_MAJOR);
return -1;
}
return 0;
}
/* This will be set after dlm_controld is started. */
#define DLM_CLUSTER_NAME_PATH "/sys/kernel/config/dlm/cluster/cluster_name"
static int read_cluster_name(char *clustername)
{
static const char close_error_msg[] = "read_cluster_name: close_error %d";
char *n;
int fd;
int rv;
if (daemon_test) {
sprintf(clustername, "%s", "test");
return 0;
}
fd = open(DLM_CLUSTER_NAME_PATH, O_RDONLY);
if (fd < 0) {
log_debug("read_cluster_name: open error %d, check dlm_controld", fd);
return fd;
}
rv = read(fd, clustername, MAX_ARGS);
if (rv < 0) {
log_error("read_cluster_name: cluster name read error %d, check dlm_controld", fd);
if (close(fd))
log_error(close_error_msg, fd);
return rv;
}
n = strstr(clustername, "\n");
if (n)
*n = '\0';
if (close(fd))
log_error(close_error_msg, fd);
return 0;
}
int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
{
char clustername[MAX_ARGS+1];
char lock_args_version[MAX_ARGS+1];
int rv;
memset(clustername, 0, sizeof(clustername));
memset(lock_args_version, 0, sizeof(lock_args_version));
snprintf(lock_args_version, MAX_ARGS, "%u.%u.%u",
VG_LOCK_ARGS_MAJOR, VG_LOCK_ARGS_MINOR, VG_LOCK_ARGS_PATCH);
rv = read_cluster_name(clustername);
if (rv < 0)
return -EMANAGER;
if (strlen(clustername) + strlen(lock_args_version) + 2 > MAX_ARGS) {
log_error("init_vg_dlm args too long");
return -EARGS;
}
snprintf(vg_args, MAX_ARGS, "%s:%s", lock_args_version, clustername);
rv = 0;
log_debug("init_vg_dlm done %s vg_args %s", ls_name, vg_args);
return rv;
}
int lm_prepare_lockspace_dlm(struct lockspace *ls)
{
char sys_clustername[MAX_ARGS+1];
char arg_clustername[MAX_ARGS+1];
struct lm_dlm *lmd;
int rv;
memset(sys_clustername, 0, sizeof(sys_clustername));
memset(arg_clustername, 0, sizeof(arg_clustername));
rv = read_cluster_name(sys_clustername);
if (rv < 0)
return -EMANAGER;
if (!ls->vg_args[0]) {
/* global lockspace has no vg args */
goto skip_args;
}
rv = check_args_version(ls->vg_args);
if (rv < 0)
return -EARGS;
rv = cluster_name_from_args(ls->vg_args, arg_clustername);
if (rv < 0) {
log_error("prepare_lockspace_dlm %s no cluster name from args %s", ls->name, ls->vg_args);
return -EARGS;
}
if (strcmp(sys_clustername, arg_clustername)) {
log_error("prepare_lockspace_dlm %s mismatching cluster names sys %s arg %s",
ls->name, sys_clustername, arg_clustername);
return -EARGS;
}
skip_args:
lmd = malloc(sizeof(struct lm_dlm));
if (!lmd)
return -ENOMEM;
ls->lm_data = lmd;
return 0;
}
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt)
{
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
if (daemon_test)
return 0;
if (adopt)
lmd->dh = dlm_open_lockspace(ls->name);
else
lmd->dh = dlm_new_lockspace(ls->name, 0600, DLM_LSFL_NEWEXCL);
if (!lmd->dh) {
log_error("add_lockspace_dlm %s adopt %d error", ls->name, adopt);
free(lmd);
ls->lm_data = NULL;
return -1;
}
return 0;
}
int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg)
{
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
int rv;
if (daemon_test)
goto out;
/*
* If free_vg is set, it means we are doing vgremove, and we may want
* to tell any other nodes to leave the lockspace. This is not really
* necessary since there should be no harm in having an unused
* lockspace sitting around. A new "notification lock" would need to
* be added with a callback to signal this.
*/
rv = dlm_release_lockspace(ls->name, lmd->dh, 1);
if (rv < 0) {
log_error("rem_lockspace_dlm error %d", rv);
return rv;
}
out:
free(lmd);
ls->lm_data = NULL;
if (!strcmp(ls->name, gl_lsname_dlm))
gl_running_dlm = 0;
return 0;
}
static int lm_add_resource_dlm(struct lockspace *ls, struct resource *r, int with_lock_nl)
{
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
uint32_t flags = 0;
char *buf;
int rv;
if (r->type == LD_RT_GL || r->type == LD_RT_VG) {
buf = malloc(sizeof(struct val_blk) + DLM_LVB_LEN);
if (!buf)
return -ENOMEM;
memset(buf, 0, sizeof(struct val_blk) + DLM_LVB_LEN);
rdd->vb = (struct val_blk *)buf;
rdd->lksb.sb_lvbptr = buf + sizeof(struct val_blk);
flags |= LKF_VALBLK;
}
if (!with_lock_nl)
goto out;
/* because this is a new NL lock request */
flags |= LKF_EXPEDITE;
if (daemon_test)
goto out;
rv = dlm_ls_lock_wait(lmd->dh, LKM_NLMODE, &rdd->lksb, flags,
r->name, strlen(r->name),
0, NULL, NULL, NULL);
if (rv < 0) {
log_error("S %s R %s add_resource_dlm lock error %d", ls->name, r->name, rv);
return rv;
}
out:
return 0;
}
int lm_rem_resource_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;
int rv = 0;
if (daemon_test)
goto out;
lksb = &rdd->lksb;
if (!lksb->sb_lkid)
goto out;
rv = dlm_ls_unlock_wait(lmd->dh, lksb->sb_lkid, 0, lksb);
if (rv < 0) {
log_error("S %s R %s rem_resource_dlm unlock error %d", ls->name, r->name, rv);
}
out:
if (rdd->vb)
free(rdd->vb);
memset(rdd, 0, sizeof(struct rd_dlm));
r->lm_init = 0;
return rv;
}
static int to_dlm_mode(int ld_mode)
{
switch (ld_mode) {
case LD_LK_EX:
return LKM_EXMODE;
case LD_LK_SH:
return LKM_PRMODE;
};
return -1;
}
static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
uint32_t *r_version)
{
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
struct dlm_lksb *lksb;
uint32_t flags = 0;
int mode;
int rv;
*r_version = 0;
if (!r->lm_init) {
rv = lm_add_resource_dlm(ls, r, 0);
if (rv < 0)
return rv;
r->lm_init = 1;
}
lksb = &rdd->lksb;
flags |= LKF_PERSISTENT;
flags |= LKF_ORPHAN;
if (rdd->vb)
flags |= LKF_VALBLK;
mode = to_dlm_mode(ld_mode);
if (mode < 0) {
log_error("adopt_dlm invalid mode %d", ld_mode);
rv = -EINVAL;
goto fail;
}
log_debug("S %s R %s adopt_dlm", ls->name, r->name);
if (daemon_test)
return 0;
/*
* dlm returns 0 for success, -EAGAIN if an orphan is
* found with another mode, and -ENOENT if no orphan.
*
* cast/bast/param are (void *)1 because the kernel
* returns errors if some are null.
*/
rv = dlm_ls_lockx(lmd->dh, mode, lksb, flags,
r->name, strlen(r->name), 0,
(void *)1, (void *)1, (void *)1,
NULL, NULL);
if (rv == -EAGAIN) {
log_debug("S %s R %s adopt_dlm adopt mode %d try other mode",
ls->name, r->name, ld_mode);
rv = -EUCLEAN;
goto fail;
}
if (rv < 0) {
log_debug("S %s R %s adopt_dlm mode %d flags %x error %d errno %d",
ls->name, r->name, mode, flags, rv, errno);
goto fail;
}
/*
* FIXME: For GL/VG locks we probably want to read the lvb,
* especially if adopting an ex lock, because when we
* release this adopted ex lock we may want to write new
* lvb values based on the current lvb values (at lease
* in the GL case where we increment the current values.)
*
* It should be possible to read the lvb by requesting
* this lock in the same mode it's already in.
*/
return rv;
fail:
lm_rem_resource_dlm(ls, r);
return rv;
}
/*
* Use PERSISTENT so that if lvmlockd exits while holding locks,
* the locks will remain orphaned in the dlm, still protecting what
* they were acquired to protect.
*/
int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
uint32_t *r_version, 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;
int mode;
int rv;
if (adopt) {
/* 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);
}
if (!r->lm_init) {
rv = lm_add_resource_dlm(ls, r, 1);
if (rv < 0)
return rv;
r->lm_init = 1;
}
lksb = &rdd->lksb;
flags |= LKF_CONVERT;
flags |= LKF_NOQUEUE;
flags |= LKF_PERSISTENT;
if (rdd->vb)
flags |= LKF_VALBLK;
mode = to_dlm_mode(ld_mode);
if (mode < 0) {
log_error("lock_dlm invalid mode %d", ld_mode);
return -EINVAL;
}
log_debug("S %s R %s lock_dlm", ls->name, r->name);
if (daemon_test) {
*r_version = 0;
return 0;
}
rv = dlm_ls_lock_wait(lmd->dh, mode, lksb, flags,
r->name, strlen(r->name),
0, NULL, NULL, NULL);
if (rv == -EAGAIN) {
log_error("S %s R %s lock_dlm mode %d rv EAGAIN", ls->name, r->name, mode);
return -EAGAIN;
}
if (rv < 0) {
log_error("S %s R %s lock_dlm error %d", ls->name, r->name, rv);
return rv;
}
if (rdd->vb) {
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;
goto out;
}
memcpy(&vb, lksb->sb_lvbptr, sizeof(struct val_blk));
vb_version = le16_to_cpu(vb.version);
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",
ls->name, r->name, *r_version);
}
out:
return 0;
}
int lm_convert_dlm(struct lockspace *ls, struct resource *r,
int ld_mode, uint32_t r_version)
{
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;
uint32_t mode;
uint32_t flags = 0;
int rv;
log_debug("S %s R %s convert_dlm", ls->name, r->name);
flags |= LKF_CONVERT;
flags |= LKF_NOQUEUE;
flags |= LKF_PERSISTENT;
if (rdd->vb && r_version && (r->mode == LD_LK_EX)) {
if (!rdd->vb->version) {
/* first time vb has been written */
rdd->vb->version = cpu_to_le16(VAL_BLK_VERSION);
}
rdd->vb->r_version = cpu_to_le32(r_version);
memcpy(lksb->sb_lvbptr, rdd->vb, sizeof(struct val_blk));
log_debug("S %s R %s convert_dlm set r_version %u",
ls->name, r->name, r_version);
flags |= LKF_VALBLK;
}
mode = to_dlm_mode(ld_mode);
if (daemon_test)
return 0;
rv = dlm_ls_lock_wait(lmd->dh, mode, lksb, flags,
r->name, strlen(r->name),
0, NULL, NULL, NULL);
if (rv == -EAGAIN) {
/* FIXME: When does this happen? Should something different be done? */
log_error("S %s R %s convert_dlm mode %d rv EAGAIN", ls->name, r->name, mode);
return -EAGAIN;
}
if (rv < 0) {
log_error("S %s R %s convert_dlm error %d", ls->name, r->name, rv);
}
return rv;
}
int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
uint32_t r_version, uint32_t lmuf_flags)
{
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;
uint32_t flags = 0;
int rv;
log_debug("S %s R %s unlock_dlm r_version %u flags %x",
ls->name, r->name, r_version, lmuf_flags);
/*
* Do not set PERSISTENT, because we don't need an orphan
* NL lock to protect anything.
*/
flags |= LKF_CONVERT;
if (rdd->vb && r_version && (r->mode == LD_LK_EX)) {
if (!rdd->vb->version) {
/* first time vb has been written */
rdd->vb->version = cpu_to_le16(VAL_BLK_VERSION);
}
if (r_version)
rdd->vb->r_version = cpu_to_le32(r_version);
memcpy(lksb->sb_lvbptr, rdd->vb, sizeof(struct val_blk));
log_debug("S %s R %s unlock_dlm set r_version %u",
ls->name, r->name, r_version);
flags |= LKF_VALBLK;
}
if (daemon_test)
return 0;
rv = dlm_ls_lock_wait(lmd->dh, LKM_NLMODE, lksb, flags,
r->name, strlen(r->name),
0, NULL, NULL, NULL);
if (rv < 0) {
log_error("S %s R %s unlock_dlm error %d", ls->name, r->name, rv);
}
return rv;
}
/*
* This list could be read from dlm_controld via libdlmcontrol,
* but it's simpler to get it from sysfs.
*/
#define DLM_LOCKSPACES_PATH "/sys/kernel/config/dlm/cluster/spaces"
int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
{
static const char closedir_err_msg[] = "lm_get_lockspace_dlm: closedir failed";
struct lockspace *ls;
struct dirent *de;
DIR *ls_dir;
if (!(ls_dir = opendir(DLM_LOCKSPACES_PATH)))
return -ECONNREFUSED;
while ((de = readdir(ls_dir))) {
if (de->d_name[0] == '.')
continue;
if (strncmp(de->d_name, LVM_LS_PREFIX, strlen(LVM_LS_PREFIX)))
continue;
if (!(ls = alloc_lockspace())) {
if (closedir(ls_dir))
log_error(closedir_err_msg);
return -ENOMEM;
}
ls->lm_type = LD_LM_DLM;
strncpy(ls->name, de->d_name, MAX_NAME);
strncpy(ls->vg_name, ls->name + strlen(LVM_LS_PREFIX), MAX_NAME);
list_add_tail(&ls->list, ls_rejoin);
}
if (closedir(ls_dir))
log_error(closedir_err_msg);
return 0;
}
int lm_is_running_dlm(void)
{
char sys_clustername[MAX_ARGS+1];
int rv;
memset(sys_clustername, 0, sizeof(sys_clustername));
rv = read_cluster_name(sys_clustername);
if (rv < 0)
return 0;
return 1;
}

View File

@@ -0,0 +1,577 @@
/*
* Copyright (C) 2014-2015 Red Hat, Inc.
*
* 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.
*/
#ifndef _LVM_LVMLOCKD_INTERNAL_H
#define _LVM_LVMLOCKD_INTERNAL_H
#define MAX_NAME 64
#define MAX_ARGS 64
#define R_NAME_GL_DISABLED "_GLLK_disabled"
#define R_NAME_GL "GLLK"
#define R_NAME_VG "VGLK"
#define S_NAME_GL_DLM "lvm_global"
#define LVM_LS_PREFIX "lvm_" /* ls name is prefix + vg_name */
/* global lockspace name for sanlock is a vg name */
/* lock manager types */
enum {
LD_LM_NONE = 0,
LD_LM_UNUSED = 1, /* place holder so values match lib/locking/lvmlockd.h */
LD_LM_DLM = 2,
LD_LM_SANLOCK = 3,
};
/* operation types */
enum {
LD_OP_HELLO = 1,
LD_OP_QUIT,
LD_OP_INIT,
LD_OP_FREE,
LD_OP_START,
LD_OP_STOP,
LD_OP_LOCK,
LD_OP_UPDATE,
LD_OP_CLOSE,
LD_OP_ENABLE,
LD_OP_DISABLE,
LD_OP_START_WAIT,
LD_OP_STOP_ALL,
LD_OP_DUMP_INFO,
LD_OP_DUMP_LOG,
LD_OP_RENAME_BEFORE,
LD_OP_RENAME_FINAL,
LD_OP_RUNNING_LM,
LD_OP_FIND_FREE_LOCK,
LD_OP_FORGET_VG_NAME,
LD_OP_KILL_VG,
LD_OP_DROP_VG,
};
/* resource types */
enum {
LD_RT_GL = 1,
LD_RT_VG,
LD_RT_LV,
};
/* lock modes, more restrictive must be larger value */
enum {
LD_LK_IV = -1,
LD_LK_UN = 0,
LD_LK_NL = 1,
LD_LK_SH = 2,
LD_LK_EX = 3,
};
struct list_head {
struct list_head *next, *prev;
};
struct client {
struct list_head list;
pthread_mutex_t mutex;
int pid;
int fd;
int pi;
uint32_t id;
unsigned int recv : 1;
unsigned int dead : 1;
unsigned int poll_ignore : 1;
char name[MAX_NAME+1];
};
#define LD_AF_PERSISTENT 0x00000001
#define LD_AF_UNUSED 0x00000002 /* use me */
#define LD_AF_UNLOCK_CANCEL 0x00000004
#define LD_AF_NEXT_VERSION 0x00000008
#define LD_AF_WAIT 0x00000010
#define LD_AF_FORCE 0x00000020
#define LD_AF_EX_DISABLE 0x00000040
#define LD_AF_ENABLE 0x00000080
#define LD_AF_DISABLE 0x00000100
#define LD_AF_SEARCH_LS 0x00000200
#define LD_AF_WAIT_STARTING 0x00001000
#define LD_AF_DUP_GL_LS 0x00002000
#define LD_AF_INACTIVE_LS 0x00004000
#define LD_AF_ADD_LS_ERROR 0x00008000
#define LD_AF_ADOPT 0x00010000
#define LD_AF_WARN_GL_REMOVED 0x00020000
/*
* Number of times to repeat a lock request after
* a lock conflict (-EAGAIN) if unspecified in the
* request.
*/
#define DEFAULT_MAX_RETRIES 4
struct action {
struct list_head list;
uint32_t client_id;
uint32_t flags; /* LD_AF_ */
uint32_t version;
uint64_t host_id;
int8_t op; /* operation type LD_OP_ */
int8_t rt; /* resource type LD_RT_ */
int8_t mode; /* lock mode LD_LK_ */
int8_t lm_type; /* lock manager: LM_DLM, LM_SANLOCK */
int retries;
int max_retries;
int result;
int lm_rv; /* return value from lm_ function */
char vg_uuid[64];
char vg_name[MAX_NAME+1];
char lv_name[MAX_NAME+1];
char lv_uuid[MAX_NAME+1];
char vg_args[MAX_ARGS+1];
char lv_args[MAX_ARGS+1];
char vg_sysid[MAX_NAME+1];
};
struct resource {
struct list_head list; /* lockspace.resources */
char name[MAX_NAME+1]; /* vg name or lv name */
int8_t type; /* resource type LD_RT_ */
int8_t mode;
unsigned int sh_count; /* number of sh locks on locks list */
uint32_t version;
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;
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 */
};
#define LD_LF_PERSISTENT 0x00000001
struct lock {
struct list_head list; /* resource.locks */
int8_t mode; /* lock mode LD_LK_ */
uint32_t version;
uint32_t flags; /* LD_LF_ */
uint32_t client_id; /* may be 0 for persistent or internal locks */
};
struct lockspace {
struct list_head list; /* lockspaces */
char name[MAX_NAME+1];
char vg_name[MAX_NAME+1];
char vg_uuid[64];
char vg_args[MAX_ARGS+1]; /* lock manager specific args */
char vg_sysid[MAX_NAME+1];
int8_t lm_type; /* lock manager: LM_DLM, LM_SANLOCK */
void *lm_data;
uint64_t host_id;
uint64_t free_lock_offset; /* start search for free lock here */
uint32_t start_client_id; /* client_id that started the lockspace */
pthread_t thread; /* makes synchronous lock requests */
pthread_cond_t cond;
pthread_mutex_t mutex;
unsigned int create_fail : 1;
unsigned int create_done : 1;
unsigned int thread_work : 1;
unsigned int thread_stop : 1;
unsigned int thread_done : 1;
unsigned int sanlock_gl_enabled: 1;
unsigned int sanlock_gl_dup: 1;
unsigned int free_vg: 1;
unsigned int kill_vg: 1;
unsigned int drop_vg: 1;
struct list_head actions; /* new client actions */
struct list_head resources; /* resource/lock state for gl/vg/lv */
};
#define VAL_BLK_VERSION 0x0101
struct val_blk {
uint16_t version;
uint16_t flags;
uint32_t r_version;
};
/* lm_unlock flags */
#define LMUF_FREE_VG 0x00000001
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
static inline void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
static inline void __list_del(struct list_head *prev, struct list_head *next)
{
next->prev = prev;
prev->next = next;
}
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}
static inline int list_empty(const struct list_head *head)
{
return head->next == head;
}
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member)
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
/* to improve readability */
#define WAIT 1
#define NO_WAIT 0
#define FORCE 1
#define NO_FORCE 0
/*
* global variables
*/
#ifndef EXTERN
#define EXTERN extern
#define INIT(X)
#else
#undef EXTERN
#define EXTERN
#define INIT(X) =X
#endif
/*
* gl_type_static and gl_use_ are set by command line or config file
* to specify whether the global lock comes from dlm or sanlock.
* Without a static setting, lvmlockd will figure out where the
* global lock should be (but it could get mixed up in cases where
* both sanlock and dlm vgs exist.)
*
* gl_use_dlm means that the gl should come from lockspace gl_lsname_dlm
* gl_use_sanlock means that the gl should come from lockspace gl_lsname_sanlock
*
* gl_use_dlm has precedence over gl_use_sanlock, so if a node sees both
* dlm and sanlock vgs, it will use the dlm gl.
*
* gl_use_ is set when the first evidence of that lm_type is seen
* in any command.
*
* gl_lsname_sanlock is set when the first vg is seen in which an
* enabled gl is exists, or when init_vg creates a vg with gl enabled,
* or when enable_gl is used.
*
* gl_lsname_sanlock is cleared when free_vg deletes a vg with gl enabled
* or when disable_gl matches.
*/
EXTERN int gl_running_dlm;
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 daemon_test; /* run as much as possible without a live lock manager */
EXTERN int daemon_debug;
EXTERN int daemon_host_id;
EXTERN const char *daemon_host_id_file;
EXTERN int sanlock_io_timeout;
/*
* This flag is set to 1 if we see multiple vgs with the global
* lock enabled. While this is set, we return a special flag
* with the vg lock result indicating to the lvm command that
* there is a duplicate gl in the vg which should be resolved.
* While this is set, find_lockspace_name has the side job of
* counting the number of lockspaces with enabled gl's so that
* this can be set back to zero when the duplicates are disabled.
*/
EXTERN int sanlock_gl_dup;
void log_level(int level, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
#define log_debug(fmt, args...) log_level(LOG_DEBUG, fmt, ##args)
#define log_error(fmt, args...) log_level(LOG_ERR, fmt, ##args)
#define log_warn(fmt, args...) log_level(LOG_WARNING, fmt, ##args)
struct lockspace *alloc_lockspace(void);
int lockspaces_empty(void);
int last_string_from_args(char *args_in, char *last);
int version_from_args(char *args, unsigned int *major, unsigned int *minor, unsigned int *patch);
#ifdef LOCKDDLM_SUPPORT
int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
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);
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,
uint32_t r_version, uint32_t lmu_flags);
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);
static inline int lm_support_dlm(void)
{
return 1;
}
#else
static inline int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
{
return -1;
}
static inline int lm_prepare_lockspace_dlm(struct lockspace *ls)
{
return -1;
}
static inline int lm_add_lockspace_dlm(struct lockspace *ls, int adopt)
{
return -1;
}
static inline int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg)
{
return -1;
}
static inline int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
uint32_t *r_version, int adopt)
{
return -1;
}
static inline int lm_convert_dlm(struct lockspace *ls, struct resource *r,
int ld_mode, uint32_t r_version)
{
return -1;
}
static inline int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
uint32_t r_version, uint32_t lmu_flags)
{
return -1;
}
static inline int lm_rem_resource_dlm(struct lockspace *ls, struct resource *r)
{
return -1;
}
static inline int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
{
return -1;
}
static inline int lm_data_size_dlm(void)
{
return -1;
}
static inline int lm_is_running_dlm(void)
{
return 0;
}
static inline int lm_support_dlm(void)
{
return 0;
}
#endif /* dlm support */
#ifdef LOCKDSANLOCK_SUPPORT
int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, uint64_t free_offset);
int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r);
int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
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);
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,
uint32_t r_version, uint32_t lmu_flags);
int lm_able_gl_sanlock(struct lockspace *ls, int enable);
int lm_ex_disable_gl_sanlock(struct lockspace *ls);
int lm_hosts_sanlock(struct lockspace *ls, int notify);
int lm_rem_resource_sanlock(struct lockspace *ls, struct resource *r);
int lm_gl_is_enabled(struct lockspace *ls);
int lm_get_lockspaces_sanlock(struct list_head *ls_rejoin);
int lm_data_size_sanlock(void);
int lm_is_running_sanlock(void);
int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset);
static inline int lm_support_sanlock(void)
{
return 1;
}
#else
static inline int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
{
return -1;
}
static inline int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, uint64_t free_offset)
{
return -1;
}
static inline int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r)
{
return -1;
}
static inline int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
{
return -1;
}
static inline int lm_prepare_lockspace_sanlock(struct lockspace *ls)
{
return -1;
}
static inline int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt)
{
return -1;
}
static inline int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg)
{
return -1;
}
static inline int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
uint32_t *r_version, int *retry, int adopt)
{
return -1;
}
static inline int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
int ld_mode, uint32_t r_version)
{
return -1;
}
static inline int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
uint32_t r_version, uint32_t lmu_flags)
{
return -1;
}
static inline int lm_able_gl_sanlock(struct lockspace *ls, int enable)
{
return -1;
}
static inline int lm_ex_disable_gl_sanlock(struct lockspace *ls)
{
return -1;
}
static inline int lm_hosts_sanlock(struct lockspace *ls, int notify)
{
return -1;
}
static inline int lm_rem_resource_sanlock(struct lockspace *ls, struct resource *r)
{
return -1;
}
static inline int lm_gl_is_enabled(struct lockspace *ls)
{
return -1;
}
static inline int lm_get_lockspaces_sanlock(struct list_head *ls_rejoin)
{
return -1;
}
static inline int lm_data_size_sanlock(void)
{
return -1;
}
static inline int lm_is_running_sanlock(void)
{
return 0;
}
static inline int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset)
{
return -1;
}
static inline int lm_support_sanlock(void)
{
return 0;
}
#endif /* sanlock support */
#endif /* _LVM_LVMLOCKD_INTERNAL_H */

File diff suppressed because it is too large Load Diff

1
daemons/lvmpolld/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
lvmpolld

View File

@@ -38,8 +38,7 @@ CFLAGS += $(DAEMON_CFLAGS)
lvmpolld: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
$(top_builddir)/libdaemon/server/libdaemonserver.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \
$(DL_LIBS) $(LVMLIBS) $(LIBS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LVMLIBS) $(LIBS)
install_lvmpolld: lvmpolld
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)

View File

@@ -18,19 +18,14 @@
#ifndef _LVM_LVMPOLLD_COMMON_H
#define _LVM_LVMPOLLD_COMMON_H
#include "configure.h"
#define _REENTRANT
#define _GNU_SOURCE
#define _FILE_OFFSET_BITS 64
#include "libdevmapper.h"
#include "tool.h"
#include "lvmpolld-cmd-utils.h"
#include "lvmpolld-protocol.h"
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#endif /* _LVM_LVMPOLLD_COMMON_H */

View File

@@ -529,7 +529,7 @@ static response progress_info(client_handle h, struct lvmpolld_state *ls, reques
if (st.polling_finished)
r = daemon_reply_simple(LVMPD_RESP_FINISHED,
"reason = %s", st.cmd_state.signal ? LVMPD_REAS_SIGNAL : LVMPD_REAS_RETCODE,
LVMPD_PARM_VALUE " = %d", st.cmd_state.signal ?: st.cmd_state.retcode,
LVMPD_PARM_VALUE " = %d", (int64_t)(st.cmd_state.signal ?: st.cmd_state.retcode),
NULL);
else
r = daemon_reply_simple(LVMPD_RESP_IN_PROGRESS, NULL);
@@ -566,6 +566,8 @@ static struct lvmpolld_lv *construct_pdlv(request req, struct lvmpolld_state *ls
return NULL;
}
pdlv->cmdargv = cmdargv;
cmdenvp = cmdenvp_ctr(pdlv);
if (!cmdenvp) {
pdlv_destroy(pdlv);
@@ -573,7 +575,6 @@ static struct lvmpolld_lv *construct_pdlv(request req, struct lvmpolld_state *ls
return NULL;
}
pdlv->cmdargv = cmdargv;
pdlv->cmdenvp = cmdenvp;
return pdlv;
@@ -749,6 +750,7 @@ 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;
@@ -851,7 +853,7 @@ enum action_index {
ACTION_MAX /* keep at the end */
};
static const action_fn_t const actions[] = { [ACTION_DUMP] = action_dump };
static const action_fn_t actions[ACTION_MAX] = { [ACTION_DUMP] = action_dump };
static int _make_action(enum action_index idx, void *args)
{
@@ -956,7 +958,7 @@ int main(int argc, char *argv[])
break;
case 't': /* --timeout in seconds */
if (!process_timeout_arg(optarg, &di.max_timeouts)) {
fprintf(stderr, "Invalid value of timeout parameter");
fprintf(stderr, "Invalid value of timeout parameter.\n");
exit(EXIT_FAILURE);
}
/* 0 equals to wait indefinitely */

View File

@@ -325,6 +325,7 @@ struct lvmpolld_thread_data *lvmpolld_thread_data_constructor(struct lvmpolld_lv
data->pdlv = NULL;
data->line = NULL;
data->line_size = 0;
data->fout = data->ferr = NULL;
data->outpipe[0] = data->outpipe[1] = data->errpipe[0] = data->errpipe[1] = -1;
@@ -365,7 +366,8 @@ void lvmpolld_thread_data_destroy(void *thread_private)
pdst_unlock(data->pdlv->pdst);
}
dm_free(data->line);
/* may get reallocated in getline(). dm_free must not be used */
free(data->line);
if (data->fout && !fclose(data->fout))
data->outpipe[0] = -1;
@@ -374,16 +376,16 @@ void lvmpolld_thread_data_destroy(void *thread_private)
data->errpipe[0] = -1;
if (data->outpipe[0] >= 0)
close(data->outpipe[0]);
(void) close(data->outpipe[0]);
if (data->outpipe[1] >= 0)
close(data->outpipe[1]);
(void) close(data->outpipe[1]);
if (data->errpipe[0] >= 0)
close(data->errpipe[0]);
(void) close(data->errpipe[0]);
if (data->errpipe[1] >= 0)
close(data->errpipe[1]);
(void) close(data->errpipe[1]);
dm_free(data);
}

View File

@@ -137,6 +137,17 @@ hosts. Overall, this is not hard, but the devil is in the details. I would
possibly disable lvmetad for clustered volume groups in the first phase and
only proceed when the local mode is robust and well tested.
With lvmlockd, lvmetad state is kept up to date by flagging either an
individual VG as "invalid", or the global state as "invalid". When either
the VG or the global state are read, this invalid flag is returned along
with the data. The client command can check for this invalid state and
decide to read the information from disk rather than use the stale cached
data. After the latest data is read from disk, the command may choose to
send it to lvmetad to update the cache. lvmlockd uses version numbers
embedded in its VG and global locks to detect when cached data becomes
invalid, and it then tells lvmetad to set the related invalid flag.
dct, 2015-06-23
Protocol & co.
--------------

View File

@@ -3,11 +3,13 @@
@top_srcdir@/daemons/lvmetad/lvmetad-client.h
@top_srcdir@/daemons/lvmpolld/lvmpolld-protocol.h
@top_srcdir@/daemons/lvmpolld/polling_ops.h
@top_srcdir@/daemons/lvmlockd/lvmlockd-client.h
@top_srcdir@/liblvm/lvm2app.h
@top_srcdir@/lib/activate/activate.h
@top_srcdir@/lib/activate/targets.h
@top_srcdir@/lib/cache/lvmcache.h
@top_srcdir@/lib/cache/lvmetad.h
@top_srcdir@/lib/locking/lvmlockd.h
@top_srcdir@/lib/commands/toolcontext.h
@top_srcdir@/lib/config/config.h
@top_srcdir@/lib/config/config_settings.h
@@ -74,3 +76,4 @@
@top_srcdir@/libdm/misc/kdev_t.h
@top_srcdir@/po/pogen.h
@top_srcdir@/tools/lvm2cmd.h
@top_srcdir@/tools/tool.h

View File

@@ -20,8 +20,12 @@ include $(top_builddir)/make.tmpl
all: .symlinks_created
.symlinks_created: .symlinks
find . -maxdepth 1 -type l -exec $(RM) \{\} \;
LINKS := $(shell find . -maxdepth 1 -type l)
.symlinks_created: .symlinks
ifneq (,$(firstword $(LINKS)))
$(RM) $(LINKS)
endif
for i in `cat $<`; do $(LN_S) $$i ; done
touch $@
@@ -31,5 +35,5 @@ device-mapper: all
cflow: all
DISTCLEAN_TARGETS += $(shell find . -maxdepth 1 -type l)
DISTCLEAN_TARGETS += .include_symlinks .symlinks_created .symlinks
DISTCLEAN_TARGETS += .symlinks
CLEAN_TARGETS += $(LINKS) .include_symlinks .symlinks_created

View File

@@ -82,7 +82,6 @@ SOURCES =\
format_text/format-text.c \
format_text/import.c \
format_text/import_vsn1.c \
format_text/tags.c \
format_text/text_label.c \
freeseg/freeseg.c \
label/label.c \
@@ -123,11 +122,6 @@ SOURCES =\
uuid/uuid.c \
zero/zero.c
ifeq ("@HAVE_REALTIME@", "yes")
SOURCES +=\
misc/timestamp.c
endif
ifeq ("@LVM1@", "internal")
SOURCES +=\
format1/disk-rep.c \
@@ -201,6 +195,11 @@ ifeq ("@BUILD_LVMPOLLD@", "yes")
lvmpolld/lvmpolld-client.c
endif
ifeq ("@BUILD_LVMLOCKD@", "yes")
SOURCES +=\
locking/lvmlockd.c
endif
ifeq ("@DMEVENTD@", "yes")
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd
LIBS += -ldevmapper-event

View File

@@ -180,7 +180,7 @@ int lv_passes_auto_activation_filter(struct cmd_context *cmd, struct logical_vol
{
const struct dm_config_node *cn;
if (!(cn = find_config_tree_node(cmd, activation_auto_activation_volume_list_CFG, NULL))) {
if (!(cn = find_config_tree_array(cmd, activation_auto_activation_volume_list_CFG, NULL))) {
log_verbose("activation/auto_activation_volume_list configuration setting "
"not defined: All logical volumes will be auto-activated.");
return 1;
@@ -467,7 +467,7 @@ static int _passes_activation_filter(struct cmd_context *cmd,
{
const struct dm_config_node *cn;
if (!(cn = find_config_tree_node(cmd, activation_volume_list_CFG, NULL))) {
if (!(cn = find_config_tree_array(cmd, activation_volume_list_CFG, NULL))) {
log_verbose("activation/volume_list configuration setting "
"not defined: Checking only host tags for %s/%s",
lv->vg->name, lv->name);
@@ -496,7 +496,7 @@ static int _passes_readonly_filter(struct cmd_context *cmd,
{
const struct dm_config_node *cn;
if (!(cn = find_config_tree_node(cmd, activation_read_only_volume_list_CFG, NULL)))
if (!(cn = find_config_tree_array(cmd, activation_read_only_volume_list_CFG, NULL)))
return 0;
return _lv_passes_volumes_filter(cmd, lv, cn, activation_read_only_volume_list_CFG);
@@ -648,8 +648,8 @@ static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv,
* in progress - as only those could lead to opened files
*/
if (with_open_count) {
if (locking_is_clustered())
sync_local_dev_names(cmd); /* Wait to have udev in sync */
if (locking_is_clustered() && !sync_local_dev_names(cmd)) /* Wait to have udev in sync */
return_0;
else if (fs_has_non_delete_ops())
fs_unlock(); /* For non clustered - wait if there are non-delete ops */
}
@@ -1813,7 +1813,9 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
goto_out;
/* Ignore origin_only unless LV is origin in both old and new metadata */
if (!lv_is_thin_volume(ondisk_lv) && !(lv_is_origin(ondisk_lv) && lv_is_origin(incore_lv)))
/* or LV is thin or thin pool volume */
if (!lv_is_thin_volume(ondisk_lv) && !lv_is_thin_pool(ondisk_lv) &&
!(lv_is_origin(ondisk_lv) && lv_is_origin(incore_lv)))
laopts->origin_only = 0;
if (test_mode()) {
@@ -1987,7 +1989,6 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
const struct logical_volume *lv_to_free = NULL;
struct lvinfo info;
int r = 0;
int messages_only = 0;
if (!activation())
return 1;
@@ -1995,10 +1996,7 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
if (!lv && !(lv_to_free = lv = lv_from_lvid(cmd, lvid_s, 0)))
goto_out;
if (lv_is_thin_pool(lv) && laopts->origin_only)
messages_only = 1;
if (!lv_is_origin(lv) && !lv_is_thin_volume(lv))
if (!lv_is_origin(lv) && !lv_is_thin_volume(lv) && !lv_is_thin_pool(lv))
laopts->origin_only = 0;
if (test_mode()) {
@@ -2010,13 +2008,15 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
log_debug_activation("Resuming LV %s/%s%s%s%s.", lv->vg->name, lv->name,
error_if_not_active ? "" : " if active",
laopts->origin_only ? " without snapshots" : "",
laopts->origin_only ?
(lv_is_thin_pool(lv) ? " pool only" :
lv_is_thin_volume(lv) ? " thin only" : " without snapshots") : "",
laopts->revert ? " (reverting)" : "");
if (!lv_info(cmd, lv, laopts->origin_only, &info, 0, 0))
goto_out;
if (!info.exists || !(info.suspended || messages_only)) {
if (!info.exists || !info.suspended) {
if (error_if_not_active)
goto_out;
r = 1;
@@ -2272,6 +2272,7 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
if (info.exists && !info.suspended && info.live_table &&
(info.read_only == read_only_lv(lv, laopts))) {
r = 1;
log_debug_activation("Volume is already active.");
goto out;
}

View File

@@ -60,6 +60,7 @@ struct dev_manager {
uint32_t pvmove_mirror_count;
int flush_required;
int activation; /* building activation tree */
int suspend; /* building suspend tree */
int skip_external_lv;
struct dm_list pending_delete; /* str_list of dlid(s) with pending delete */
unsigned track_pending_delete;
@@ -445,6 +446,78 @@ out:
return r;
}
static int _device_is_suspended(int major, int minor)
{
struct dm_task *dmt;
struct dm_info info;
int r = 0;
if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
return 0;
if (!dm_task_set_major_minor(dmt, major, minor, 1))
goto_out;
if (activation_checks() && !dm_task_enable_checks(dmt))
goto_out;
if (!dm_task_run(dmt) ||
!dm_task_get_info(dmt, &info)) {
log_error("Failed to get info for device %d:%d", major, minor);
goto out;
}
r = info.exists && info.suspended;
out:
dm_task_destroy(dmt);
return r;
}
static int _ignore_suspended_snapshot_component(struct device *dev)
{
struct dm_task *dmt;
void *next = NULL;
char *params, *target_type = NULL;
uint64_t start, length;
int major1, minor1, major2, minor2;
int r = 0;
if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
return_0;
if (!dm_task_set_major_minor(dmt, MAJOR(dev->dev), MINOR(dev->dev), 1))
goto_out;
if (activation_checks() && !dm_task_enable_checks(dmt))
goto_out;
if (!dm_task_run(dmt)) {
log_error("Failed to get state of snapshot or snapshot origin device");
goto out;
}
do {
next = dm_get_next_target(dmt, next, &start, &length, &target_type, &params);
if (!strcmp(target_type, "snapshot")) {
if (sscanf(params, "%d:%d %d:%d", &major1, &minor1, &major2, &minor2) != 4) {
log_error("Incorrect snapshot table found");
goto_out;
}
r = r || _device_is_suspended(major1, minor1) || _device_is_suspended(major2, minor2);
} else if (!strcmp(target_type, "snapshot-origin")) {
if (sscanf(params, "%d:%d", &major1, &minor1) != 2) {
log_error("Incorrect snapshot-origin table found");
goto_out;
}
r = r || _device_is_suspended(major1, minor1);
}
} while (next);
out:
dm_task_destroy(dmt);
return r;
}
/*
* device_is_usable
* @dev
@@ -553,15 +626,25 @@ int device_is_usable(struct device *dev, struct dev_usable_check_params check)
* supported anymore and in general using mirrors in a stack
* is disabled by default (with a warning that if enabled,
* it could cause various deadlocks).
* This is former check used, but it's not correct as it
* disables snapshot-origins to be used in a stack in
* general, not just over mirrors!
* Similar situation can happen with RAID devices where
* a RAID device can be snapshotted.
* If one of the RAID legs are down and we're doing
* lvconvert --repair, there's a time period in which
* snapshot components are (besides other devs) suspended.
* See also https://bugzilla.redhat.com/show_bug.cgi?id=1219222
* for an example where this causes problems.
*
* This is a quick check for now, but replace it with more
* robust and better check that would check the stack
* correctly, not just snapshots but any cobimnation possible
* in a stack - use proper dm tree to check this instead.
*/
/*if (check.check_suspended && target_type && !strcmp(target_type, "snapshot-origin")) {
log_debug_activation("%s: Snapshot-origin device %s not usable.",
dev_name(dev), name);
if (check.check_suspended && target_type &&
(!strcmp(target_type, "snapshot") || !strcmp(target_type, "snapshot-origin")) &&
_ignore_suspended_snapshot_component(dev)) {
log_debug_activation("%s: %s device %s not usable.", dev_name(dev), target_type, name);
goto out;
}*/
}
if (target_type && strcmp(target_type, "error"))
only_error_target = 0;
@@ -1835,7 +1918,6 @@ struct pool_cb_data {
int skip_zero; /* to skip zeroed device header (check first 64B) */
int exec; /* which binary to call */
int opts;
const char *defaults;
const char *global;
};
@@ -1843,7 +1925,6 @@ static int _pool_callback(struct dm_tree_node *node,
dm_node_callback_t type, void *cb_data)
{
int ret, status, fd;
char *split;
const struct dm_config_node *cn;
const struct dm_config_value *cv;
const struct pool_cb_data *data = cb_data;
@@ -1858,23 +1939,19 @@ static int _pool_callback(struct dm_tree_node *node,
if (!*argv[0])
return 1; /* Checking disabled */
if ((cn = find_config_tree_node(mlv->vg->cmd, data->opts, NULL))) {
for (cv = cn->v; cv && args < 16; cv = cv->next) {
if (cv->type != DM_CFG_STRING) {
log_error("Invalid string in config file: "
"global/%s_check_options",
data->global);
return 0;
}
argv[++args] = cv->v.str;
}
} else {
/* Use default options (no support for options with spaces) */
if (!(split = dm_pool_strdup(data->dm->mem, data->defaults))) {
log_error("Failed to duplicate defaults.");
if (!(cn = find_config_tree_array(mlv->vg->cmd, data->opts, NULL))) {
log_error(INTERNAL_ERROR "Unable to find configuration for pool check options.");
return 0;
}
for (cv = cn->v; cv && args < 16; cv = cv->next) {
if (cv->type != DM_CFG_STRING) {
log_error("Invalid string in config file: "
"global/%s_check_options",
data->global);
return 0;
}
args = dm_split_words(split, 16, 0, (char**) argv + 1);
argv[++args] = cv->v.str;
}
if (args == 16) {
@@ -1965,14 +2042,12 @@ static int _pool_register_callback(struct dev_manager *dm,
data->skip_zero = 1;
data->exec = global_thin_check_executable_CFG;
data->opts = global_thin_check_options_CFG;
data->defaults = DEFAULT_THIN_CHECK_OPTION1 " " DEFAULT_THIN_CHECK_OPTION2;
data->global = "thin";
} else if (lv_is_cache(lv)) { /* cache pool */
data->pool_lv = first_seg(lv)->pool_lv;
data->skip_zero = dm->activation;
data->exec = global_cache_check_executable_CFG;
data->opts = global_cache_check_options_CFG;
data->defaults = DEFAULT_CACHE_CHECK_OPTION1;
data->global = "cache";
} else {
log_error(INTERNAL_ERROR "Registering unsupported pool callback.");
@@ -1984,6 +2059,11 @@ static int _pool_register_callback(struct dev_manager *dm,
return 1;
}
/* Declaration to resolve suspend tree and message passing for thin-pool */
static int _add_target_to_dtree(struct dev_manager *dm,
struct dm_tree_node *dnode,
struct lv_segment *seg,
struct lv_activate_opts *laopts);
/*
* Add LV and any known dependencies
*/
@@ -2052,15 +2132,43 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
*/
if (!_add_dev_to_dtree(dm, dtree, lv, lv_layer(lv)))
return_0;
/*
* TODO: change API and move this code
* Could be easier to handle this in _add_dev_to_dtree()
* and base this according to info.exists ?
*/
if (!dm->activation) {
/* Setup callback for non-activation partial tree */
/* Activation gets own callback when needed */
/* TODO: extend _cached_dm_info() to return dnode */
if (!(uuid = build_dm_uuid(dm->mem, lv, lv_layer(lv))))
return_0;
if ((node = dm_tree_find_node_by_uuid(dtree, uuid)) &&
!_pool_register_callback(dm, node, lv))
return_0;
if ((node = dm_tree_find_node_by_uuid(dtree, uuid))) {
if (origin_only) {
struct lv_activate_opts laopts = {
.origin_only = 1,
.send_messages = 1 /* Node with messages */
};
/*
* Add some messsages if right node exist in the table only
* when building SUSPEND tree for origin-only thin-pool.
*
* TODO: Fix call of '_add_target_to_dtree()' to add message
* to thin-pool node as we already know the pool node exists
* in the table. Any better/cleaner API way ?
*
* Probably some 'new' target method to add messages for any node?
*/
if (dm->suspend &&
!dm_list_empty(&(first_seg(lv)->thin_messages)) &&
!_add_target_to_dtree(dm, node, first_seg(lv), &laopts))
return_0;
} else {
/* Setup callback for non-activation partial tree */
/* Activation gets own callback when needed */
/* TODO: extend _cached_dm_info() to return dnode */
if (!_pool_register_callback(dm, node, lv))
return_0;
}
}
}
}
@@ -2158,7 +2266,7 @@ static struct dm_tree *_create_partial_dtree(struct dev_manager *dm, const struc
dm_tree_set_optional_uuid_suffixes(dtree, &uuid_suffix_list[0]);
if (!_add_lv_to_dtree(dm, dtree, lv, (lv_is_origin(lv) || lv_is_thin_volume(lv)) ? origin_only : 0))
if (!_add_lv_to_dtree(dm, dtree, lv, (lv_is_origin(lv) || lv_is_thin_volume(lv) || lv_is_thin_pool(lv)) ? origin_only : 0))
goto_bad;
return dtree;
@@ -2613,7 +2721,7 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
return_0;
/* Add pool layer */
if (seg->pool_lv &&
if (seg->pool_lv && !laopts->origin_only &&
!_add_new_lv_to_dtree(dm, dtree, seg->pool_lv, laopts,
lv_layer(seg->pool_lv)))
return_0;
@@ -3042,7 +3150,10 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
int r = 0;
if (action < DM_ARRAY_SIZE(_action_names))
log_debug_activation("Creating %s tree for %s.", _action_names[action], lv->name);
log_debug_activation("Creating %s%s tree for %s.",
_action_names[action],
(laopts->origin_only) ? " origin-only" : "",
display_lvname(lv));
/* Some LV can be used for top level tree */
/* TODO: add more.... */
@@ -3052,6 +3163,7 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
}
/* Some targets may build bigger tree for activation */
dm->activation = ((action == PRELOAD) || (action == ACTIVATE));
dm->suspend = (action == SUSPEND_WITH_LOCKFS) || (action == SUSPEND);
if (!(dtree = _create_partial_dtree(dm, lv, laopts->origin_only)))
return_0;
@@ -3096,7 +3208,9 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
case PRELOAD:
case ACTIVATE:
/* Add all required new devices to tree */
if (!_add_new_lv_to_dtree(dm, dtree, lv, laopts, (lv_is_origin(lv) && laopts->origin_only) ? "real" : NULL))
if (!_add_new_lv_to_dtree(dm, dtree, lv, laopts,
(lv_is_origin(lv) && laopts->origin_only) ? "real" :
(lv_is_thin_pool(lv) && laopts->origin_only) ? "tpool" : NULL))
goto_out;
/* Preload any devices required before any suspensions */
@@ -3134,7 +3248,6 @@ out_no_root:
int dev_manager_activate(struct dev_manager *dm, const struct logical_volume *lv,
struct lv_activate_opts *laopts)
{
laopts->send_messages = 1;
if (!_tree_action(dm, lv, laopts, ACTIVATE))
return_0;

53
lib/cache/lvmcache.c vendored
View File

@@ -56,6 +56,7 @@ struct lvmcache_vginfo {
char _padding[7];
struct lvmcache_vginfo *next; /* Another VG with same name? */
char *creation_host;
char *lock_type;
uint32_t mda_checksum;
size_t mda_size;
size_t vgmetadata_size;
@@ -1447,7 +1448,7 @@ static int _lvmcache_update_vgname(struct lvmcache_info *info,
}
static int _lvmcache_update_vgstatus(struct lvmcache_info *info, uint32_t vgstatus,
const char *creation_host)
const char *creation_host, const char *lock_type)
{
if (!info || !info->vginfo)
return 1;
@@ -1460,11 +1461,11 @@ static int _lvmcache_update_vgstatus(struct lvmcache_info *info, uint32_t vgstat
info->vginfo->status = vgstatus;
if (!creation_host)
return 1;
goto set_lock_type;
if (info->vginfo->creation_host && !strcmp(creation_host,
info->vginfo->creation_host))
return 1;
goto set_lock_type;
if (info->vginfo->creation_host)
dm_free(info->vginfo->creation_host);
@@ -1478,6 +1479,24 @@ static int _lvmcache_update_vgstatus(struct lvmcache_info *info, uint32_t vgstat
log_debug_cache("lvmcache: %s: VG %s: Set creation host to %s.",
dev_name(info->dev), info->vginfo->vgname, creation_host);
set_lock_type:
if (!lock_type)
goto out;
if (info->vginfo->lock_type && !strcmp(lock_type, info->vginfo->lock_type))
goto out;
if (info->vginfo->lock_type)
dm_free(info->vginfo->lock_type);
if (!(info->vginfo->lock_type = dm_strdup(lock_type))) {
log_error("cache creation host alloc failed for %s",
lock_type);
return 0;
}
out:
return 1;
}
@@ -1546,7 +1565,7 @@ int lvmcache_update_vgname_and_id(struct lvmcache_info *info, struct lvmcache_vg
if (!_lvmcache_update_vgname(info, vgname, vgid, vgsummary->vgstatus,
vgsummary->creation_host, info->fmt) ||
!_lvmcache_update_vgid(info, info->vginfo, vgid) ||
!_lvmcache_update_vgstatus(info, vgsummary->vgstatus, vgsummary->creation_host) ||
!_lvmcache_update_vgstatus(info, vgsummary->vgstatus, vgsummary->creation_host, vgsummary->lock_type) ||
!_lvmcache_update_vg_mda_info(info, vgsummary->mda_checksum, vgsummary->mda_size))
return_0;
@@ -1561,7 +1580,8 @@ int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted)
struct lvmcache_vgsummary vgsummary = {
.vgname = vg->name,
.vgstatus = vg->status,
.vgid = vg->id
.vgid = vg->id,
.lock_type = vg->lock_type
};
pvid_s[sizeof(pvid_s) - 1] = '\0';
@@ -1856,14 +1876,12 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
}
/*
* FIXME: when could this ever happen?
* If this does happen, identify when/why here, and
* if not, remove this code.
* This happens when running pvcreate on an existing PV.
*/
if (strcmp(pvid_s, existing->dev->pvid)) {
log_warn("Replacing dev %s pvid %s with dev %s pvid %s",
dev_name(existing->dev), existing->dev->pvid,
dev_name(dev), pvid_s);
log_verbose("Replacing dev %s pvid %s with dev %s pvid %s",
dev_name(existing->dev), existing->dev->pvid,
dev_name(dev), pvid_s);
}
/*
@@ -2327,3 +2345,16 @@ int lvmcache_lookup_mda(struct lvmcache_vgsummary *vgsummary)
return 0;
}
int lvmcache_contains_lock_type_sanlock(struct cmd_context *cmd)
{
struct lvmcache_vginfo *vginfo;
dm_list_iterate_items(vginfo, &_vginfos) {
if (vginfo->lock_type && !strcmp(vginfo->lock_type, "sanlock"))
return 1;
}
return 0;
}

14
lib/cache/lvmcache.h vendored
View File

@@ -39,11 +39,23 @@ struct disk_locn;
struct lvmcache_vginfo;
/*
* vgsummary represents a summary of the VG that is read
* without a lock. The info does not come through vg_read(),
* but through reading mdas. It provides information about
* the VG that is needed to lock the VG and then read it fully
* with vg_read(), after which the VG summary should be checked
* against the full VG metadata to verify it was correct (since
* it was read without a lock.)
*
* Once read, vgsummary information is saved in lvmcache_vginfo.
*/
struct lvmcache_vgsummary {
const char *vgname;
struct id vgid;
uint64_t vgstatus;
char *creation_host;
const char *lock_type;
uint32_t mda_checksum;
size_t mda_size;
};
@@ -176,4 +188,6 @@ int lvmcache_found_duplicate_pvs(void);
void lvmcache_set_preferred_duplicates(const char *vgid);
int lvmcache_contains_lock_type_sanlock(struct cmd_context *cmd);
#endif

540
lib/cache/lvmetad.c vendored
View File

@@ -22,6 +22,7 @@
#include "format-text.h" // TODO for disk_locn, used as a DA representation
#include "crc.h"
#include "lvm-signal.h"
#include "lvmlockd.h"
#define SCAN_TIMEOUT_SECONDS 80
#define MAX_RESCANS 10 /* Maximum number of times to scan all PVs and retry if the daemon returns a token mismatch error */
@@ -34,12 +35,13 @@ static char *_lvmetad_token = NULL;
static const char *_lvmetad_socket = NULL;
static struct cmd_context *_lvmetad_cmd = NULL;
static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg);
void lvmetad_disconnect(void)
{
if (_lvmetad_connected)
daemon_close(_lvmetad);
_lvmetad_connected = 0;
_lvmetad_cmd = NULL;
}
void lvmetad_init(struct cmd_context *cmd)
@@ -47,6 +49,10 @@ void lvmetad_init(struct cmd_context *cmd)
if (!_lvmetad_use && !access(getenv("LVM_LVMETAD_PIDFILE") ? : LVMETAD_PIDFILE, F_OK))
log_warn("WARNING: lvmetad is running but disabled."
" Restart lvmetad before enabling it!");
if (_lvmetad_connected)
log_debug(INTERNAL_ERROR "Refreshing lvmetad global handle while connection with the daemon is active");
_lvmetad_cmd = cmd;
}
@@ -142,7 +148,7 @@ static int _lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler
static daemon_reply _lvmetad_send(const char *id, ...)
{
va_list ap;
daemon_reply repl;
daemon_reply repl = { 0 };
daemon_request req;
unsigned num_rescans = 0;
unsigned total_usecs_waited = 0;
@@ -152,8 +158,10 @@ static daemon_reply _lvmetad_send(const char *id, ...)
retry:
req = daemon_request_make(id);
if (_lvmetad_token)
daemon_request_extend(req, "token = %s", _lvmetad_token, NULL);
if (_lvmetad_token && !daemon_request_extend(req, "token = %s", _lvmetad_token, NULL)) {
repl.error = ENOMEM;
return repl;
}
va_start(ap, id);
daemon_request_extend_v(req, ap);
@@ -395,9 +403,26 @@ static int _pv_populate_lvmcache(struct cmd_context *cmd,
return 1;
}
static int _pv_update_struct_pv(struct physical_volume *pv, struct format_instance *fid)
{
struct lvmcache_info *info;
if ((info = lvmcache_info_from_pvid((const char *)&pv->id, 0))) {
pv->label_sector = lvmcache_get_label(info)->sector;
pv->dev = lvmcache_device(info);
if (!pv->dev)
pv->status |= MISSING_PV;
if (!lvmcache_fid_add_mdas_pv(info, fid))
return_0;
pv->fid = fid;
} else
pv->status |= MISSING_PV; /* probably missing */
return 1;
}
struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgname, const char *vgid)
{
struct volume_group *vg = NULL;
struct volume_group *vg2 = NULL;
daemon_reply reply;
int found;
char uuid[64];
@@ -409,7 +434,6 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgna
struct format_type *fmt;
struct dm_config_node *pvcn;
struct pv_list *pvl;
struct lvmcache_info *info;
if (!lvmetad_active())
return NULL;
@@ -460,22 +484,38 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgna
for (pvcn = pvcn->child; pvcn; pvcn = pvcn->sib)
_pv_populate_lvmcache(cmd, pvcn, fmt, 0);
if ((pvcn = dm_config_find_node(top, "metadata/outdated_pvs")))
for (pvcn = pvcn->child; pvcn; pvcn = pvcn->sib)
_pv_populate_lvmcache(cmd, pvcn, fmt, 0);
top->key = name;
if (!(vg = import_vg_from_config_tree(reply.cft, fid)))
if (!(vg = import_vg_from_lvmetad_config_tree(reply.cft, fid)))
goto_out;
/*
* locking may have detected a newer vg version and
* invalidated the cached vg.
*/
if (dm_config_find_node(reply.cft->root, "vg_invalid")) {
log_debug_lvmetad("Update invalid lvmetad cache for VG %s", vgname);
vg2 = lvmetad_pvscan_vg(cmd, vg);
release_vg(vg);
vg = vg2;
fid = vg->fid;
}
dm_list_iterate_items(pvl, &vg->pvs) {
if ((info = lvmcache_info_from_pvid((const char *)&pvl->pv->id, 0))) {
pvl->pv->label_sector = lvmcache_get_label(info)->sector;
pvl->pv->dev = lvmcache_device(info);
if (!pvl->pv->dev)
pvl->pv->status |= MISSING_PV;
if (!lvmcache_fid_add_mdas_pv(info, fid)) {
vg = NULL;
goto_out; /* FIXME error path */
}
} else
pvl->pv->status |= MISSING_PV; /* probably missing */
if (!_pv_update_struct_pv(pvl->pv, fid)) {
vg = NULL;
goto_out; /* FIXME error path */
}
}
dm_list_iterate_items(pvl, &vg->pvs_outdated) {
if (!_pv_update_struct_pv(pvl->pv, fid)) {
vg = NULL;
goto_out; /* FIXME error path */
}
}
lvmcache_update_vg(vg, 0);
@@ -912,6 +952,51 @@ int lvmetad_pv_found(const struct id *pvid, struct device *dev, const struct for
daemon_reply_int(reply, "seqno_after", -1) != daemon_reply_int(reply, "seqno_before", -1)))
log_warn("WARNING: Inconsistent metadata found for VG %s", vg->name);
/*
* pvscan --cache does not perform any lvmlockd locking, and
* pvscan --cache -aay skips autoactivation in lockd VGs.
*
* pvscan --cache populates lvmetad with VG metadata from disk.
* No lvmlockd locking is needed. It is expected that lockd VG
* metadata that is read by pvscan and populated in lvmetad may
* be immediately stale due to changes to the VG from other hosts
* during or after this pvscan. This is normal and not a problem.
* When a subsequent lvm command uses the VG, it will lock the VG
* with lvmlockd, read the VG from lvmetad, and update the cached
* copy from disk if necessary.
*
* pvscan --cache -aay does not activate LVs in lockd VGs because
* activation requires locking, and a lock-start operation is needed
* on a lockd VG before any locking can be performed in it.
*
* An equivalent of pvscan --cache -aay for lockd VGs is:
* 1. pvscan --cache
* 2. vgchange --lock-start
* 3. vgchange -aay -S 'locktype=sanlock || locktype=dlm'
*
* [We could eventually add support for autoactivating lockd VGs
* using pvscan by incorporating the lock start step (which can
* take a long time), but there may be a better option than
* continuing to overload pvscan.]
*
* Stages of starting a lockd VG:
*
* . pvscan --cache populates lockd VGs in lvmetad without locks,
* and this initial cached copy may quickly become stale.
*
* . vgchange --lock-start VG reads the VG without the VG lock
* because no locks are available until the locking is started.
* It only uses the VG name and lock_type from the VG metadata,
* and then only uses it to start the VG lockspace in lvmlockd.
*
* . Further lvm commands, e.g. activation, can then lock the VG
* with lvmlockd and use current VG metdata.
*/
if (handler && vg && is_lockd_type(vg->lock_type)) {
log_debug_lvmetad("Skip pvscan activation for lockd type VG %s", vg->name);
handler = NULL;
}
if (result && handler) {
status = daemon_reply_str(reply, "status", "<missing>");
vgname = daemon_reply_str(reply, "vgname", "<missing>");
@@ -979,7 +1064,8 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
struct _lvmetad_pvscan_baton *b = baton;
struct volume_group *this;
this = mda_is_ignored(mda) ? NULL : mda->ops->vg_read(b->fid, "", mda, NULL, NULL, 1);
if (!(this = mda_is_ignored(mda) ? NULL : mda->ops->vg_read(b->fid, "", mda, NULL, NULL, 1)))
return 1;
/* FIXME Also ensure contents match etc. */
if (!b->vg || this->seqno > b->vg->seqno)
@@ -990,6 +1076,100 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
return 1;
}
/*
* The lock manager may detect that the vg cached in lvmetad is out of date,
* 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.
*/
static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg)
{
struct volume_group *vg_ret = NULL;
struct dm_config_tree *vgmeta_ret = NULL;
struct dm_config_tree *vgmeta;
struct pv_list *pvl;
struct lvmcache_info *info;
struct format_instance *fid;
struct format_instance_ctx fic = { .type = 0 };
struct _lvmetad_pvscan_baton baton;
dm_list_iterate_items(pvl, &vg->pvs) {
/* missing pv */
if (!pvl->pv->dev)
continue;
if (!(info = lvmcache_info_from_pvid((const char *)&pvl->pv->id, 0))) {
log_error("Failed to find cached info for PV %s.", pv_dev_name(pvl->pv));
return NULL;
}
baton.vg = NULL;
baton.fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info), &fic);
if (!baton.fid)
return NULL;
if (baton.fid->fmt->features & FMT_OBSOLETE) {
log_error("WARNING: Ignoring obsolete format of metadata (%s) on device %s when using lvmetad",
baton.fid->fmt->name, dev_name(pvl->pv->dev));
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
return NULL;
}
lvmcache_foreach_mda(info, _lvmetad_pvscan_single, &baton);
if (!baton.vg) {
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
return NULL;
}
if (!(vgmeta = export_vg_to_config_tree(baton.vg))) {
log_error("VG export to config tree failed");
release_vg(baton.vg);
return NULL;
}
if (!vgmeta_ret) {
vgmeta_ret = vgmeta;
} else {
if (!compare_config(vgmeta_ret->root, vgmeta->root)) {
log_error("VG metadata comparison failed");
dm_config_destroy(vgmeta);
dm_config_destroy(vgmeta_ret);
release_vg(baton.vg);
return NULL;
}
dm_config_destroy(vgmeta);
}
release_vg(baton.vg);
}
if (vgmeta_ret) {
fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info), &fic);
if (!(vg_ret = import_vg_from_config_tree(vgmeta_ret, fid))) {
log_error("VG import from config tree failed");
lvmcache_fmt(info)->ops->destroy_instance(fid);
goto out;
}
/*
* Update lvmetad with the newly read version of the VG.
* The "precommitted" name is a misnomer in this case,
* but that is the field which lvmetad_vg_update() uses
* to send the metadata cft to lvmetad.
*/
vg_ret->cft_precommitted = vgmeta_ret;
if (!lvmetad_vg_update(vg_ret))
log_error("Failed to update lvmetad with new VG meta");
vg_ret->cft_precommitted = NULL;
dm_config_destroy(vgmeta_ret);
}
out:
return vg_ret;
}
int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
activation_handler handler, int ignore_obsolete)
{
@@ -1139,3 +1319,327 @@ int lvmetad_pvscan_foreign_vgs(struct cmd_context *cmd, activation_handler handl
{
return _lvmetad_pvscan_all_devs(cmd, handler, 1);
}
int lvmetad_vg_clear_outdated_pvs(struct volume_group *vg)
{
char uuid[64];
daemon_reply reply;
int result;
if (!id_write_format(&vg->id, uuid, sizeof(uuid)))
return_0;
reply = _lvmetad_send("vg_clear_outdated_pvs", "vgid = %s", uuid, NULL);
result = _lvmetad_handle_reply(reply, "clear the list of outdated PVs", vg->name, NULL);
daemon_reply_destroy(reply);
return result;
}
/*
* Records the state of cached PVs in lvmetad so we can look for changes
* after rescanning.
*/
struct pv_cache_list {
struct dm_list list;
dev_t devt;
struct id pvid;
const char *vgid;
unsigned found : 1;
unsigned update_udev : 1;
};
/*
* Get the list of PVs known to lvmetad.
*/
static int _lvmetad_get_pv_cache_list(struct cmd_context *cmd, struct dm_list *pvc_list)
{
daemon_reply reply;
struct dm_config_node *cn;
struct pv_cache_list *pvcl;
const char *pvid_txt;
const char *vgid;
if (!lvmetad_active())
return 1;
log_debug_lvmetad("Asking lvmetad for complete list of known PVs");
reply = _lvmetad_send("pv_list", NULL);
if (!_lvmetad_handle_reply(reply, "list PVs", "", NULL)) {
log_error("lvmetad message failed.");
daemon_reply_destroy(reply);
return_0;
}
if ((cn = dm_config_find_node(reply.cft->root, "physical_volumes"))) {
for (cn = cn->child; cn; cn = cn->sib) {
if (!(pvcl = dm_pool_zalloc(cmd->mem, sizeof(*pvcl)))) {
log_error("pv_cache_list allocation failed.");
return 0;
}
pvid_txt = cn->key;
if (!id_read_format(&pvcl->pvid, pvid_txt)) {
stack;
continue;
}
pvcl->devt = dm_config_find_int(cn->child, "device", 0);
if ((vgid = dm_config_find_str(cn->child, "vgid", NULL)))
pvcl->vgid = dm_pool_strdup(cmd->mem, vgid);
dm_list_add(pvc_list, &pvcl->list);
}
}
daemon_reply_destroy(reply);
return 1;
}
/*
* Opening the device RDWR should trigger a udev db update.
* FIXME: is there a better way to update the udev db than
* doing an open/close of the device? - For example writing
* "change" to /sys/block/<device>/uevent?
*/
static void _update_pv_in_udev(struct cmd_context *cmd, dev_t devt)
{
struct device *dev;
log_debug_devs("device %d:%d open to update udev",
(int)MAJOR(devt), (int)MINOR(devt));
if (!(dev = dev_cache_get_by_devt(devt, cmd->lvmetad_filter))) {
log_error("_update_pv_in_udev no dev found");
return;
}
if (!dev_open(dev)) {
stack;
return;
}
if (!dev_close(dev))
stack;
}
/*
* Compare before and after PV lists from before/after rescanning,
* and update udev db for changes.
*
* For PVs that have changed pvid or vgid in lvmetad from rescanning,
* there may be information in the udev database to update, so open
* these devices to trigger a udev update.
*
* "before" refers to the list of pvs from lvmetad before rescanning
* "after" refers to the list of pvs from lvmetad after rescanning
*
* Comparing both lists, we can see which PVs changed (pvid or vgid),
* and trigger a udev db update for those.
*/
static void _update_changed_pvs_in_udev(struct cmd_context *cmd,
struct dm_list *pvc_before,
struct dm_list *pvc_after)
{
struct pv_cache_list *before;
struct pv_cache_list *after;
char id_before[ID_LEN + 1] __attribute__((aligned(8)));
char id_after[ID_LEN + 1] __attribute__((aligned(8)));
int found;
dm_list_iterate_items(before, pvc_before) {
found = 0;
dm_list_iterate_items(after, pvc_after) {
if (after->found)
continue;
if (before->devt != after->devt)
continue;
if (!id_equal(&before->pvid, &after->pvid)) {
memset(id_before, 0, sizeof(id_before));
memset(id_after, 0, sizeof(id_after));
strncpy(&id_before[0], (char *) &before->pvid, sizeof(id_before) - 1);
strncpy(&id_after[0], (char *) &after->pvid, sizeof(id_after) - 1);
log_debug_devs("device %d:%d changed pvid from %s to %s",
(int)MAJOR(before->devt), (int)MINOR(before->devt),
id_before, id_after);
before->update_udev = 1;
} else if ((before->vgid && !after->vgid) ||
(after->vgid && !before->vgid) ||
(before->vgid && after->vgid && strcmp(before->vgid, after->vgid))) {
log_debug_devs("device %d:%d changed vg from %s to %s",
(int)MAJOR(before->devt), (int)MINOR(before->devt),
before->vgid ?: "none", after->vgid ?: "none");
before->update_udev = 1;
}
after->found = 1;
before->found = 1;
found = 1;
break;
}
if (!found) {
memset(id_before, 0, sizeof(id_before));
strncpy(&id_before[0], (char *) &before->pvid, sizeof(id_before) - 1);
log_debug_devs("device %d:%d pvid %s vg %s is gone",
(int)MAJOR(before->devt), (int)MINOR(before->devt),
id_before, before->vgid ? before->vgid : "none");
before->update_udev = 1;
}
}
dm_list_iterate_items(before, pvc_before) {
if (before->update_udev)
_update_pv_in_udev(cmd, before->devt);
}
dm_list_iterate_items(after, pvc_after) {
if (after->update_udev)
_update_pv_in_udev(cmd, after->devt);
}
}
/*
* Before this command was run, some external entity may have
* invalidated lvmetad's cache of global information, e.g. lvmlockd.
*
* The global information includes things like a new VG, a
* VG that was removed, the assignment of a PV to a VG;
* any change that is not isolated within a single VG.
*
* The external entity, like a lock manager, would invalidate
* the lvmetad global cache if it detected that the global
* information had been changed on disk by something other
* than a local lvm command, e.g. an lvm command on another
* host with access to the same devices. (How it detects
* the change is specific to lock manager or other entity.)
*
* The effect is that metadata on disk is newer than the metadata
* in the local lvmetad daemon, and the local lvmetad's cache
* should be updated from disk before this command uses it.
*
* So, using this function, a command checks if lvmetad's global
* cache is valid. If so, it does nothing. If not, it rescans
* devices to update the lvmetad cache, then it notifies lvmetad
* that it's cache is valid again (consistent with what's on disk.)
* This command can then go ahead and use the newly refreshed metadata.
*
* 1. Check if the lvmetad global cache is invalid.
* 2. If so, reread metadata from all devices and update the lvmetad cache.
* 3. Tell lvmetad that the global cache is now valid.
*/
void lvmetad_validate_global_cache(struct cmd_context *cmd, int force)
{
struct dm_list pvc_before; /* pv_cache_list */
struct dm_list pvc_after; /* pv_cache_list */
daemon_reply reply;
int global_invalid;
dm_list_init(&pvc_before);
dm_list_init(&pvc_after);
if (!lvmlockd_use()) {
log_error(INTERNAL_ERROR "validate global cache without lvmlockd");
return;
}
if (!lvmetad_used())
return;
log_debug_lvmetad("Validating global lvmetad cache");
if (force)
goto do_scan;
reply = daemon_send_simple(_lvmetad, "get_global_info",
"token = %s", "skip",
NULL);
if (reply.error) {
log_error("lvmetad_validate_global_cache get_global_info error %d", reply.error);
goto do_scan;
}
if (strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
log_error("lvmetad_validate_global_cache get_global_info not ok");
goto do_scan;
}
global_invalid = daemon_reply_int(reply, "global_invalid", -1);
daemon_reply_destroy(reply);
if (!global_invalid) {
/* cache is valid */
return;
}
do_scan:
/*
* Save the current state of pvs from lvmetad so after devices are
* scanned, we can compare to the new state to see if pvs changed.
*/
_lvmetad_get_pv_cache_list(cmd, &pvc_before);
/*
* Update the local lvmetad cache so it correctly reflects any
* changes made on remote hosts.
*/
lvmetad_pvscan_all_devs(cmd, NULL);
/*
* Clear the global_invalid flag in lvmetad.
* Subsequent local commands that read global state
* from lvmetad will not see global_invalid until
* another host makes another global change.
*/
reply = daemon_send_simple(_lvmetad, "set_global_info",
"token = %s", "skip",
"global_invalid = %d", 0,
NULL);
if (reply.error)
log_error("lvmetad_validate_global_cache set_global_info error %d", reply.error);
if (strcmp(daemon_reply_str(reply, "response", ""), "OK"))
log_error("lvmetad_validate_global_cache set_global_info not ok");
daemon_reply_destroy(reply);
/*
* Populate this command's lvmcache structures from lvmetad.
*/
lvmcache_seed_infos_from_lvmetad(cmd);
/*
* Update the local udev database to reflect PV changes from
* other hosts.
*
* Compare the before and after PV lists, and if a PV's
* pvid or vgid has changed, then open that device to trigger
* a uevent to update the udev db.
*
* This has no direct benefit to lvm, but is just a best effort
* attempt to keep the udev db updated and reflecting current
* lvm information.
*
* FIXME: lvmcache_seed_infos_from_lvmetad() and _lvmetad_get_pv_cache_list()
* each get pv_list from lvmetad, and they could share a single pv_list reply.
*/
if (!dm_list_empty(&pvc_before)) {
_lvmetad_get_pv_cache_list(cmd, &pvc_after);
_update_changed_pvs_in_udev(cmd, &pvc_before, &pvc_after);
}
}

18
lib/cache/lvmetad.h vendored
View File

@@ -29,8 +29,7 @@ typedef int (*activation_handler) (struct cmd_context *cmd,
#ifdef LVMETAD_SUPPORT
/*
* Initialise the communication with lvmetad. Normally called by
* lvmcache_init. Sets up a global handle for our process.
* Sets up a global handle for our process.
*/
void lvmetad_init(struct cmd_context *);
@@ -59,7 +58,9 @@ int lvmetad_socket_present(void);
/*
* Check whether lvmetad is active (where active means both that it is running
* and that we have a working connection with it).
* and that we have a working connection with it). It opens new connection
* with lvmetad in the process when lvmetad is supposed to be used and the
* connection is not open yet.
*/
int lvmetad_active(void);
@@ -70,8 +71,9 @@ int lvmetad_active(void);
void lvmetad_connect_or_warn(void);
/*
* Drop connection to lvmetad. A subsequent lvmetad_init() will re-establish
* the connection (possibly at a different socket path).
* Drop connection to lvmetad. A subsequent lvmetad_connect_or_warn or
* lvmetad_active will re-establish the connection (possibly at a
* different socket path).
*/
void lvmetad_disconnect(void);
@@ -164,6 +166,9 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
int lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler handler);
int lvmetad_pvscan_foreign_vgs(struct cmd_context *cmd, activation_handler handler);
int lvmetad_vg_clear_outdated_pvs(struct volume_group *vg);
void lvmetad_validate_global_cache(struct cmd_context *cmd, int force);
# else /* LVMETAD_SUPPORT */
# define lvmetad_init(cmd) do { } while (0)
@@ -185,10 +190,13 @@ int lvmetad_pvscan_foreign_vgs(struct cmd_context *cmd, activation_handler handl
# define lvmetad_pv_lookup(cmd, pvid, found) (0)
# define lvmetad_pv_lookup_by_dev(cmd, dev, found) (0)
# define lvmetad_vg_list_to_lvmcache(cmd) (1)
# define lvmetad_get_vgnameids(cmd, vgnameids) do { } while (0)
# define lvmetad_vg_lookup(cmd, vgname, vgid) (NULL)
# define lvmetad_pvscan_single(cmd, dev, handler, ignore_obsolete) (0)
# define lvmetad_pvscan_all_devs(cmd, handler) (0)
# define lvmetad_pvscan_foreign_vgs(cmd, handler) (0)
# define lvmetad_vg_clear_outdated_pvs(vg) (1)
# define lvmetad_validate_global_cache(cmd, force) do { } while (0)
# endif /* LVMETAD_SUPPORT */

View File

@@ -77,9 +77,13 @@ static int _cache_pool_text_import(struct lv_segment *seg,
return SEG_LOG_ERROR("policy must be a string in");
if (!(seg->policy_name = dm_pool_strdup(mem, str)))
return SEG_LOG_ERROR("Failed to duplicate policy in");
} else
} else {
/* Cannot use 'just' default, so pick one */
seg->policy_name = DEFAULT_CACHE_POOL_POLICY; /* FIXME make configurable */
/* FIXME maybe here should be always 'mq' */
log_warn("WARNING: cache_policy undefined, using default \"%s\" policy.",
seg->policy_name);
}
/*
* Read in policy args:
@@ -130,13 +134,17 @@ static int _cache_pool_text_export(const struct lv_segment *seg,
if (!(cache_mode = get_cache_pool_cachemode_name(seg)))
return_0;
if (!seg->policy_name) {
log_error(INTERNAL_ERROR "Policy name for %s is not defined.",
display_lvname(seg->lv));
return 0;
}
outf(f, "data = \"%s\"", seg_lv(seg, 0)->name);
outf(f, "metadata = \"%s\"", seg->metadata_lv->name);
outf(f, "chunk_size = %" PRIu32, seg->chunk_size);
outf(f, "cache_mode = \"%s\"", cache_mode);
if (seg->policy_name)
outf(f, "policy = \"%s\"", seg->policy_name);
outf(f, "policy = \"%s\"", seg->policy_name);
if (seg->policy_settings) {
if (strcmp(seg->policy_settings->key, "policy_settings")) {

View File

@@ -245,8 +245,10 @@ static int _parse_debug_classes(struct cmd_context *cmd)
const struct dm_config_value *cv;
int debug_classes = 0;
if (!(cn = find_config_tree_node(cmd, log_debug_classes_CFG, NULL)))
return DEFAULT_LOGGED_DEBUG_CLASSES;
if (!(cn = find_config_tree_array(cmd, log_debug_classes_CFG, NULL))) {
log_error(INTERNAL_ERROR "Unable to find configuration for log/debug_classes.");
return -1;
}
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != DM_CFG_STRING) {
@@ -413,6 +415,57 @@ static int _check_config(struct cmd_context *cmd)
return 1;
}
static const char *_set_time_format(struct cmd_context *cmd)
{
/* Compared to strftime, we do not allow "newline" character - the %n in format. */
static const char *allowed_format_chars = "aAbBcCdDeFGghHIjklmMpPrRsStTuUVwWxXyYzZ%";
static const char *allowed_alternative_format_chars_e = "cCxXyY";
static const char *allowed_alternative_format_chars_o = "deHImMSuUVwWy";
static const char *chars_to_check;
const char *tf = find_config_tree_str(cmd, report_time_format_CFG, NULL);
const char *p_fmt;
size_t i;
char c;
if (!*tf) {
log_error("Configured time format is empty string.");
goto bad;
} else {
p_fmt = tf;
while ((c = *p_fmt)) {
if (c == '%') {
c = *++p_fmt;
if (c == 'E') {
c = *++p_fmt;
chars_to_check = allowed_alternative_format_chars_e;
} else if (c == 'O') {
c = *++p_fmt;
chars_to_check = allowed_alternative_format_chars_o;
} else
chars_to_check = allowed_format_chars;
for (i = 0; chars_to_check[i]; i++) {
if (c == chars_to_check[i])
break;
}
if (!chars_to_check[i])
goto_bad;
}
else if (isprint(c))
p_fmt++;
else {
log_error("Configured time format contains non-printable characters.");
goto bad;
}
}
}
return tf;
bad:
log_error("Invalid time format \"%s\" supplied.", tf);
return NULL;
}
int process_profilable_config(struct cmd_context *cmd)
{
if (!(cmd->default_settings.unit_factor =
@@ -426,6 +479,8 @@ int process_profilable_config(struct cmd_context *cmd)
cmd->report_binary_values_as_numeric = find_config_tree_bool(cmd, report_binary_values_as_numeric_CFG, NULL);
cmd->default_settings.suffix = find_config_tree_bool(cmd, global_suffix_CFG, NULL);
cmd->report_list_item_separator = find_config_tree_str(cmd, report_list_item_separator_CFG, NULL);
if (!(cmd->time_format = _set_time_format(cmd)))
return 0;
return 1;
}
@@ -477,8 +532,6 @@ static int _process_config(struct cmd_context *cmd)
const struct dm_config_node *cn;
const struct dm_config_value *cv;
int64_t pv_min_kb;
const char *lvmetad_socket;
const char *lvmpolld_socket;
int udev_disabled = 0;
char sysfs_dir[PATH_MAX];
@@ -599,7 +652,7 @@ static int _process_config(struct cmd_context *cmd)
}
}
if ((cn = find_config_tree_node(cmd, activation_mlock_filter_CFG, NULL)))
if ((cn = find_config_tree_array(cmd, activation_mlock_filter_CFG, NULL)))
for (cv = cn->v; cv; cv = cv->next)
if ((cv->type != DM_CFG_STRING) || !cv->v.str[0])
log_error("Ignoring invalid activation/mlock_filter entry in config file");
@@ -621,41 +674,9 @@ static int _process_config(struct cmd_context *cmd)
init_detect_internal_vg_cache_corruption
(find_config_tree_bool(cmd, global_detect_internal_vg_cache_corruption_CFG, NULL));
lvmetad_disconnect();
lvmpolld_disconnect();
lvmetad_socket = getenv("LVM_LVMETAD_SOCKET");
if (!lvmetad_socket)
lvmetad_socket = DEFAULT_RUN_DIR "/lvmetad.socket";
/* TODO?
lvmetad_socket = find_config_tree_str(cmd, "lvmetad/socket_path",
DEFAULT_RUN_DIR "/lvmetad.socket");
*/
lvmetad_set_socket(lvmetad_socket);
cn = find_config_tree_node(cmd, devices_global_filter_CFG, NULL);
lvmetad_set_token(cn ? cn->v : NULL);
if (find_config_tree_int(cmd, global_locking_type_CFG, NULL) == 3 &&
find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL)) {
log_warn("WARNING: configuration setting use_lvmetad overridden to 0 due to locking_type 3. "
"Clustered environment not supported by lvmetad yet.");
lvmetad_set_active(NULL, 0);
} else
lvmetad_set_active(NULL, find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL));
lvmetad_init(cmd);
if (!_init_system_id(cmd))
return_0;
lvmpolld_socket = getenv("LVM_LVMPOLLD_SOCKET");
if (!lvmpolld_socket)
lvmpolld_socket = DEFAULT_RUN_DIR "/lvmpolld.socket";
lvmpolld_set_socket(lvmpolld_socket);
lvmpolld_set_active(find_config_tree_bool(cmd, global_use_lvmpolld_CFG, NULL));
return 1;
}
@@ -962,15 +983,9 @@ static int _init_dev_cache(struct cmd_context *cmd)
init_obtain_device_list_from_udev(device_list_from_udev);
if (!(cn = find_config_tree_node(cmd, devices_scan_CFG, NULL))) {
if (!dev_cache_add_dir("/dev")) {
log_error("Failed to add /dev to internal "
"device cache");
return 0;
}
log_verbose("device/scan not in config file: "
"Defaulting to /dev");
return 1;
if (!(cn = find_config_tree_array(cmd, devices_scan_CFG, NULL))) {
log_error(INTERNAL_ERROR "Unable to find configuration for devices/scan.");
return_0;
}
for (cv = cn->v; cv; cv = cv->next) {
@@ -1008,7 +1023,7 @@ static int _init_dev_cache(struct cmd_context *cmd)
}
}
if (!(cn = find_config_tree_node(cmd, devices_loopfiles_CFG, NULL)))
if (!(cn = find_config_tree_array(cmd, devices_loopfiles_CFG, NULL)))
return 1;
for (cv = cn->v; cv; cv = cv->next) {
@@ -1146,7 +1161,7 @@ bad:
* md component filter -> fw raid filter
*
*/
static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache)
int init_filters(struct cmd_context *cmd, unsigned load_persistent_cache)
{
const char *dev_cache;
struct dev_filter *filter = NULL, *filter_components[2] = {0};
@@ -1154,6 +1169,11 @@ static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache
const struct dm_config_node *cn;
struct timespec ts, cts;
if (!cmd->initialized.connections) {
log_error(INTERNAL_ERROR "connections must be initialized before filters");
return 0;
}
cmd->dump_filter = 0;
cmd->lvmetad_filter = _init_lvmetad_filter_chain(cmd);
@@ -1183,7 +1203,7 @@ static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache
}
/* filter component 1 */
if ((cn = find_config_tree_node(cmd, devices_filter_CFG, NULL))) {
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 */
@@ -1234,6 +1254,7 @@ static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache
dev_cache);
}
cmd->initialized.filters = 1;
return 1;
bad:
if (!filter) {
@@ -1257,6 +1278,7 @@ bad:
if (cmd->lvmetad_filter)
cmd->lvmetad_filter->destroy(cmd->lvmetad_filter);
cmd->initialized.filters = 0;
return 0;
}
@@ -1300,7 +1322,7 @@ static int _init_formats(struct cmd_context *cmd)
#ifdef HAVE_LIBDL
/* Load any formats in shared libs if not static */
if (!is_static() &&
(cn = find_config_tree_node(cmd, global_format_libraries_CFG, NULL))) {
(cn = find_config_tree_array(cmd, global_format_libraries_CFG, NULL))) {
const struct dm_config_value *cv;
struct format_type *(*init_format_fn) (struct cmd_context *);
@@ -1466,7 +1488,7 @@ static int _init_segtypes(struct cmd_context *cmd)
#ifdef HAVE_LIBDL
/* Load any formats in shared libs unless static */
if (!is_static() &&
(cn = find_config_tree_node(cmd, global_segment_libraries_CFG, NULL))) {
(cn = find_config_tree_array(cmd, global_segment_libraries_CFG, NULL))) {
const struct dm_config_value *cv;
int (*init_multiple_segtypes_fn) (struct cmd_context *,
@@ -1630,11 +1652,80 @@ static int _reopen_stream(FILE *stream, int fd, const char *mode, const char *na
return 1;
}
static int _init_lvmetad(struct cmd_context *cmd)
{
const struct dm_config_node *cn;
const char *lvmetad_socket;
lvmetad_disconnect();
lvmetad_socket = getenv("LVM_LVMETAD_SOCKET");
if (!lvmetad_socket)
lvmetad_socket = DEFAULT_RUN_DIR "/lvmetad.socket";
/* TODO?
lvmetad_socket = find_config_tree_str(cmd, "lvmetad/socket_path",
DEFAULT_RUN_DIR "/lvmetad.socket");
*/
lvmetad_set_socket(lvmetad_socket);
cn = find_config_tree_array(cmd, devices_global_filter_CFG, NULL);
lvmetad_set_token(cn ? cn->v : NULL);
if (find_config_tree_int(cmd, global_locking_type_CFG, NULL) == 3 &&
find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL)) {
log_warn("WARNING: configuration setting use_lvmetad overridden to 0 due to locking_type 3. "
"Clustered environment not supported by lvmetad yet.");
lvmetad_set_active(NULL, 0);
} else
lvmetad_set_active(NULL, find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL));
lvmetad_init(cmd);
return 1;
}
static int _init_lvmpolld(struct cmd_context *cmd)
{
const char *lvmpolld_socket;
lvmpolld_disconnect();
lvmpolld_socket = getenv("LVM_LVMPOLLD_SOCKET");
if (!lvmpolld_socket)
lvmpolld_socket = DEFAULT_RUN_DIR "/lvmpolld.socket";
lvmpolld_set_socket(lvmpolld_socket);
lvmpolld_set_active(find_config_tree_bool(cmd, global_use_lvmpolld_CFG, NULL));
return 1;
}
int init_connections(struct cmd_context *cmd)
{
if (!_init_lvmetad(cmd)) {
log_error("Failed to initialize lvmetad connection.");
goto bad;
}
if (!_init_lvmpolld(cmd)) {
log_error("Failed to initialize lvmpolld connection.");
goto bad;
}
cmd->initialized.connections = 1;
return 1;
bad:
cmd->initialized.connections = 0;
return 0;
}
/* Entry point */
struct cmd_context *create_toolcontext(unsigned is_long_lived,
const char *system_dir,
unsigned set_buffering,
unsigned threaded)
unsigned threaded,
unsigned set_connections,
unsigned set_filters)
{
struct cmd_context *cmd;
FILE *new_stream;
@@ -1772,15 +1863,12 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
goto_out;
if (!(cmd->dev_types = create_dev_types(cmd->proc_dir,
find_config_tree_node(cmd, devices_types_CFG, NULL))))
find_config_tree_array(cmd, devices_types_CFG, NULL))))
goto_out;
if (!_init_dev_cache(cmd))
goto_out;
if (!_init_filters(cmd, 1))
goto_out;
memlock_init(cmd);
if (!_init_formats(cmd))
@@ -1799,12 +1887,18 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
_init_globals(cmd);
if (set_connections && !init_connections(cmd))
return_0;
if (set_filters && !init_filters(cmd, 1))
goto_out;
cmd->default_settings.cache_vgmetadata = 1;
cmd->current_settings = cmd->default_settings;
cmd->config_initialized = 1;
cmd->initialized.config = 1;
out:
if (!cmd->config_initialized) {
if (!cmd->initialized.config) {
destroy_toolcontext(cmd);
cmd = NULL;
}
@@ -1876,14 +1970,19 @@ static void _destroy_filters(struct cmd_context *cmd)
cmd->full_filter->destroy(cmd->full_filter);
cmd->lvmetad_filter = cmd->filter = cmd->full_filter = NULL;
}
cmd->initialized.filters = 0;
}
int refresh_filters(struct cmd_context *cmd)
{
int r, saved_ignore_suspended_devices = ignore_suspended_devices();
if (!cmd->initialized.filters)
/* if filters not initialized, there's nothing to refresh */
return 1;
_destroy_filters(cmd);
if (!(r = _init_filters(cmd, 0)))
if (!(r = init_filters(cmd, 0)))
stack;
/*
@@ -1912,7 +2011,6 @@ int refresh_toolcontext(struct cmd_context *cmd)
label_exit();
_destroy_segtypes(&cmd->segtypes);
_destroy_formats(cmd, &cmd->formats);
_destroy_filters(cmd);
if (!dev_cache_exit())
stack;
@@ -1930,7 +2028,7 @@ int refresh_toolcontext(struct cmd_context *cmd)
_destroy_config(cmd);
cmd->config_initialized = 0;
cmd->initialized.config = 0;
cmd->hosttags = 0;
@@ -1987,15 +2085,12 @@ int refresh_toolcontext(struct cmd_context *cmd)
return_0;
if (!(cmd->dev_types = create_dev_types(cmd->proc_dir,
find_config_tree_node(cmd, devices_types_CFG, NULL))))
find_config_tree_array(cmd, devices_types_CFG, NULL))))
return_0;
if (!_init_dev_cache(cmd))
return_0;
if (!_init_filters(cmd, 0))
return_0;
if (!_init_formats(cmd))
return_0;
@@ -2008,7 +2103,13 @@ int refresh_toolcontext(struct cmd_context *cmd)
if (!_init_backup(cmd))
return_0;
cmd->config_initialized = 1;
cmd->initialized.config = 1;
if (cmd->initialized.connections && !init_connections(cmd))
return_0;
if (!refresh_filters(cmd))
return_0;
reset_lvm_errno(1);
return 1;

View File

@@ -60,29 +60,59 @@ struct config_tree_list {
struct dm_config_tree *cft;
};
struct cmd_context_initialized_parts {
unsigned config:1; /* used to reinitialize config if previous init was not successful */
unsigned filters:1;
unsigned connections:1;
};
/* FIXME Split into tool & library contexts */
/* command-instance-related variables needed by library */
struct cmd_context {
struct dm_pool *libmem; /* For permanent config data */
struct dm_pool *mem; /* Transient: Cleared between each command */
/*
* Memory handlers.
*/
struct dm_pool *libmem; /* for permanent config data */
struct dm_pool *mem; /* transient: cleared between each command */
const struct format_type *fmt; /* Current format to use by default */
struct format_type *fmt_backup; /* Format to use for backups */
struct dm_list formats; /* Available formats */
struct dm_list segtypes; /* Available segment types */
const char *system_id;
const char *hostname;
const char *kernel_vsn;
unsigned rand_seed;
char *linebuffer;
/*
* Command line and arguments.
*/
const char *cmd_line;
struct command *command;
char **argv;
struct arg_values *arg_values;
struct dm_list arg_value_groups;
unsigned is_long_lived:1; /* Optimises persistent_filter handling */
/*
* Format handlers.
*/
const struct format_type *fmt; /* current format to use by default */
struct format_type *fmt_backup; /* format to use for backups */
struct dm_list formats; /* available formats */
struct dm_list segtypes; /* available segment types */
/*
* Machine and system identification.
*/
const char *system_id;
const char *hostname;
const char *kernel_vsn;
/*
* Device identification.
*/
struct dev_types *dev_types; /* recognized extra device types. */
/*
* Initialization state.
*/
struct cmd_context_initialized_parts initialized;
/*
* Switches.
*/
unsigned is_long_lived:1; /* optimises persistent_filter handling */
unsigned handles_missing_pvs:1;
unsigned handles_unknown_segments:1;
unsigned use_linear_target:1;
@@ -93,59 +123,71 @@ struct cmd_context {
unsigned report_binary_values_as_numeric:1;
unsigned metadata_read_only:1;
unsigned ignore_clustered_vgs:1;
unsigned threaded:1; /* Set if running within a thread e.g. clvmd */
unsigned independent_metadata_areas:1; /* Active formats have MDAs outside PVs */
unsigned threaded:1; /* set if running within a thread e.g. clvmd */
unsigned independent_metadata_areas:1; /* active formats have MDAs outside PVs */
unsigned unknown_system_id:1;
unsigned include_foreign_vgs:1;
unsigned include_active_foreign_vgs:1;
unsigned error_foreign_vgs:1;
struct dev_types *dev_types;
unsigned include_foreign_vgs:1; /* report/display cmds can reveal foreign VGs */
unsigned include_shared_vgs:1; /* report/display cmds can reveal lockd VGs */
unsigned include_active_foreign_vgs:1; /* cmd should process foreign VGs with active LVs */
unsigned vg_read_print_access_error:1; /* print access errors from vg_read */
unsigned lockd_gl_disable:1;
unsigned lockd_vg_disable:1;
unsigned lockd_lv_disable:1;
unsigned lockd_vg_default_sh:1;
unsigned lockd_vg_enforce_sh:1;
/*
* Use of filters depends on whether lvmetad is used or not:
*
* - if lvmetad is used:
* - cmd->lvmetad_filter used when scanning devices for lvmetad
* - cmd->filter used when processing lvmetad responses
* - cmd->full_filter used for remaining situations
*
* - if lvmetad is not used:
* - cmd->lvmetad_filter is NULL
* - cmd->filter == cmd->full_filter used for all situations
*
* Filtering.
*/
struct dev_filter *lvmetad_filter;
struct dev_filter *filter;
struct dev_filter *full_filter;
int dump_filter; /* Dump filter when exiting? */
struct dev_filter *lvmetad_filter; /* pre-lvmetad filter chain */
struct dev_filter *filter; /* post-lvmetad filter chain */
struct dev_filter *full_filter; /* lvmetad_filter + filter */
int dump_filter; /* Dump filter when exiting? */
struct dm_list config_files; /* master lvm config + any existing tag configs */
struct profile_params *profile_params; /* profile handling params including loaded profile configs */
struct dm_config_tree *cft; /* the whole cascade: CONFIG_STRING -> CONFIG_PROFILE -> CONFIG_FILE/CONFIG_MERGED_FILES */
int config_initialized; /* used to reinitialize config if previous init was not successful */
struct dm_hash_table *cft_def_hash; /* config definition hash used for validity check (item type + item recognized) */
/* selected settings with original default/configured value which can be changed during cmd processing */
struct config_info default_settings;
/* may contain changed values compared to default_settings */
struct config_info current_settings;
/*
* Configuration.
*/
struct dm_list config_files; /* master lvm config + any existing tag configs */
struct profile_params *profile_params; /* profile handling params including loaded profile configs */
struct dm_config_tree *cft; /* the whole cascade: CONFIG_STRING -> CONFIG_PROFILE -> CONFIG_FILE/CONFIG_MERGED_FILES */
struct dm_hash_table *cft_def_hash; /* config definition hash used for validity check (item type + item recognized) */
struct config_info default_settings; /* selected settings with original default/configured value which can be changed during cmd processing */
struct config_info current_settings; /* may contain changed values compared to default_settings */
/*
* Archives and backups.
*/
struct archive_params *archive_params;
struct backup_params *backup_params;
const char *stripe_filler;
/* List of defined tags */
struct dm_list tags;
const char *report_list_item_separator;
/*
* Host tags.
*/
struct dm_list tags; /* list of defined tags */
int hosttags;
const char *lib_dir; /* Cache value global/library_dir */
/*
* Paths.
*/
const char *lib_dir; /* cache value global/library_dir */
char system_dir[PATH_MAX];
char dev_dir[PATH_MAX];
char proc_dir[PATH_MAX];
/*
* Buffers.
*/
char display_buffer[NAME_LEN * 10]; /* ring buffer for upto 10 longest vg/lv names */
unsigned display_lvname_idx; /* index to ring buffer */
char *linebuffer;
/*
* Others - unsorted.
*/
const char *report_list_item_separator;
const char *time_format;
unsigned rand_seed;
};
/*
@@ -155,13 +197,17 @@ struct cmd_context {
struct cmd_context *create_toolcontext(unsigned is_long_lived,
const char *system_dir,
unsigned set_buffering,
unsigned threaded);
unsigned threaded,
unsigned set_connections,
unsigned set_filters);
void destroy_toolcontext(struct cmd_context *cmd);
int refresh_toolcontext(struct cmd_context *cmd);
int refresh_filters(struct cmd_context *cmd);
int process_profilable_config(struct cmd_context *cmd);
int config_files_changed(struct cmd_context *cmd);
int init_lvmcache_orphans(struct cmd_context *cmd);
int init_filters(struct cmd_context *cmd, unsigned load_persistent_cache);
int init_connections(struct cmd_context *cmd);
struct format_type *get_format_by_name(struct cmd_context *cmd, const char *format);

View File

@@ -666,22 +666,28 @@ static void _log_type_error(const char *path, cfg_def_type_t actual,
actual_type_name, expected_type_name);
}
static struct dm_config_value *_get_def_array_values(struct dm_config_tree *cft,
const cfg_def_item_t *def)
static struct dm_config_value *_get_def_array_values(struct cmd_context *cmd,
struct dm_config_tree *cft,
const cfg_def_item_t *def,
uint32_t format_flags)
{
const char *def_enc_value;
char *enc_value, *token, *p, *r;
struct dm_config_value *array = NULL, *v = NULL, *oldv = NULL;
if (!def->default_value.v_CFG_TYPE_STRING) {
def_enc_value = cfg_def_get_default_value(cmd, def, CFG_TYPE_ARRAY, NULL);
if (!def_enc_value) {
if (!(array = dm_config_create_value(cft))) {
log_error("Failed to create default empty array for %s.", def->name);
return NULL;
}
array->type = DM_CFG_EMPTY_ARRAY;
dm_config_value_set_format_flags(array, format_flags);
return array;
}
if (!(p = token = enc_value = dm_strdup(def->default_value.v_CFG_TYPE_STRING))) {
if (!(p = token = enc_value = dm_strdup(def_enc_value))) {
log_error("_get_def_array_values: dm_strdup failed");
return NULL;
}
@@ -710,6 +716,9 @@ static struct dm_config_value *_get_def_array_values(struct dm_config_tree *cft,
dm_free(enc_value);
return NULL;
}
dm_config_value_set_format_flags(v, format_flags);
if (oldv)
oldv->next = v;
if (!array)
@@ -839,7 +848,7 @@ static int _check_value_differs_from_default(struct cft_check_handle *handle,
}
if (!v_def && (def->type & CFG_TYPE_ARRAY)) {
if (!(v_def_array = v_def_iter = _get_def_array_values(handle->cft, def)))
if (!(v_def_array = v_def_iter = _get_def_array_values(handle->cmd, handle->cft, def, 0)))
return_0;
do {
/* iterate over each element of the array and check its value */
@@ -1031,9 +1040,14 @@ static int _config_def_check_tree(struct cft_check_handle *handle,
size_t buf_size, struct dm_config_node *root)
{
struct dm_config_node *cn;
cfg_def_item_t *def;
int valid, r = 1;
size_t len;
def = cfg_def_get_item_p(root->id);
if (def->flags & CFG_SECTION_NO_CHECK)
return 1;
for (cn = root->child; cn; cn = cn->sib) {
if ((valid = _config_def_check_node(handle, vp, pvp, rp, prp,
buf_size, cn)) && !cn->v) {
@@ -1355,6 +1369,106 @@ int find_config_tree_bool(struct cmd_context *cmd, int id, struct profile *profi
return b;
}
static struct dm_config_node *_get_array_def_node(struct cmd_context *cmd,
cfg_def_item_t *def,
struct profile *profile)
{
struct dm_config_node *cn;
if (def->flags & CFG_DEFAULT_UNDEFINED)
return NULL;
if (!(cn = dm_config_create_node(cmd->cft, def->name))) {
log_error("Failed to create default array node for %s.", def->name);
return NULL;
}
if (!(cn->v = _get_def_array_values(cmd, cmd->cft, def, 0))) {
dm_pool_free(cmd->cft->mem, cn);
return_NULL;
}
return cn;
}
struct _config_array_out_handle {
struct dm_pool *mem;
char *str;
};
static int _config_array_line(const struct dm_config_node *cn, const char *line, void *baton)
{
struct _config_array_out_handle *handle = (struct _config_array_out_handle *) baton;
if (!(handle->str = dm_pool_strdup(handle->mem, line))) {
log_error("_config_array_line: dm_pool_strdup failed");
return 0;
}
return 1;
}
static void _log_array_value_used(struct dm_pool *mem, const struct dm_config_node *cn,
const char *path, int default_used)
{
struct _config_array_out_handle out_handle = { 0 };
struct dm_config_node_out_spec out_spec = { 0 };
uint32_t old_format_flags;
out_handle.mem = mem;
out_spec.line_fn = _config_array_line;
old_format_flags = dm_config_value_get_format_flags(cn->v);
dm_config_value_set_format_flags(cn->v,
DM_CONFIG_VALUE_FMT_COMMON_EXTRA_SPACES |
DM_CONFIG_VALUE_FMT_COMMON_ARRAY);
if (!dm_config_write_one_node_out(cn, &out_spec, &out_handle)) {
log_error("_log_array_value_used: failed to write node value");
out_handle.mem = NULL;
}
if (default_used)
log_very_verbose("%s not found in config: defaulting to %s",
path, out_handle.mem ? out_handle.str : "<unknown>");
else
log_very_verbose("Setting %s to %s",
path, out_handle.mem ? out_handle.str : "<unknown>");
if (out_handle.mem)
dm_pool_free(out_handle.mem, out_handle.str);
dm_config_value_set_format_flags(cn->v, old_format_flags);
}
const struct dm_config_node *find_config_tree_array(struct cmd_context *cmd, int id, struct profile *profile)
{
cfg_def_item_t *item = cfg_def_get_item_p(id);
char path[CFG_PATH_MAX_LEN];
int profile_applied;
const struct dm_config_node *cn = NULL, *cn_def = NULL;
profile_applied = _apply_local_profile(cmd, profile);
_cfg_def_make_path(path, sizeof(path), item->id, item, 0);
if (!(item->type & CFG_TYPE_ARRAY))
log_error(INTERNAL_ERROR "%s cfg tree element not declared as array.", path);
if (_config_disabled(cmd, item, path) ||
!(cn = find_config_tree_node(cmd, id, profile)))
cn_def = _get_array_def_node(cmd, item, profile);
if (cn)
_log_array_value_used(cmd->cft->mem, cn, path, 0);
else if (cn_def) {
_log_array_value_used(cmd->cft->mem, cn_def, path, 1);
cn = cn_def;
}
if (profile_applied)
remove_config_tree_by_source(cmd, profile->source);
return cn;
}
/* Insert cn2 after cn1 */
static void _insert_config_node(struct dm_config_node **cn1,
struct dm_config_node *cn2)
@@ -1553,14 +1667,9 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi
char path[CFG_PATH_MAX_LEN];
char commentline[MAX_COMMENT_LINE+1];
if (cn->id < 0)
if (cn->id <= 0)
return 1;
if (!cn->id) {
log_error(INTERNAL_ERROR "Configuration node %s has invalid id.", cn->key);
return 0;
}
if (out->tree_spec->type == CFG_DEF_TREE_LIST)
return 1;
@@ -1603,6 +1712,10 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi
if (cfg_def->flags & CFG_DEFAULT_UNDEFINED)
fprintf(out->fp, "%s# This configuration %s does not have a default value defined.\n", line, node_type_name);
if ((out->tree_spec->type == CFG_DEF_TREE_FULL) &&
(out->tree_spec->check_status[cn->id] & CFG_USED))
fprintf(out->fp, "%s# Value defined in existing configuration has been used for this setting.\n", line);
}
if (out->tree_spec->withversions) {
@@ -1620,6 +1733,16 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi
return 1;
}
static int _should_print_cfg_with_undef_def_val(struct out_baton *out, cfg_def_item_t *cfg_def,
const struct dm_config_node *cn)
{
if (!(cfg_def->flags & CFG_DEFAULT_UNDEFINED))
return 1;
/* print it only if the value is directly defined in some config = it's used */
return out->tree_spec->check_status && (out->tree_spec->check_status[cn->id] & CFG_USED);
}
static int _out_line_fn(const struct dm_config_node *cn, const char *line, void *baton)
{
struct out_baton *out = baton;
@@ -1662,14 +1785,23 @@ static int _out_line_fn(const struct dm_config_node *cn, const char *line, void
}
/* Usual tree view with nodes and their values. */
if ((out->tree_spec->type != CFG_DEF_TREE_CURRENT) &&
(out->tree_spec->type != CFG_DEF_TREE_DIFF) &&
(out->tree_spec->type != CFG_DEF_TREE_FULL) &&
(cfg_def->flags & (CFG_DEFAULT_UNDEFINED | CFG_DEFAULT_COMMENTED))) {
space_prefix = ((len = strspn(line, "\t "))) ? dm_pool_strndup(out->mem, line, len) : NULL;
fprintf(out->fp, "%s%s%s\n", space_prefix ? : "", "# ", line + len);
if (space_prefix)
dm_pool_free(out->mem, space_prefix);
} else
/* print with # at the front to comment out the line */
if (_should_print_cfg_with_undef_def_val(out, cfg_def, cn)) {
space_prefix = ((len = strspn(line, "\t "))) ? dm_pool_strndup(out->mem, line, len) : NULL;
fprintf(out->fp, "%s%s%s\n", space_prefix ? : "", "# ", line + len);
if (space_prefix)
dm_pool_free(out->mem, space_prefix);
}
return 1;
}
/* print the line as it is */
if (_should_print_cfg_with_undef_def_val(out, cfg_def, cn))
fprintf(out->fp, "%s\n", line);
return 1;
@@ -1739,15 +1871,20 @@ static struct dm_config_node *_add_def_node(struct dm_config_tree *cft,
{
struct dm_config_node *cn;
const char *str;
uint32_t format_flags = 0;
if (!(cn = dm_config_create_node(cft, def->name))) {
log_error("Failed to create default config setting node.");
return NULL;
}
if (!(def->type & CFG_TYPE_SECTION) && (!(cn->v = dm_config_create_value(cft)))) {
log_error("Failed to create default config setting node value.");
return NULL;
if (!(def->type & CFG_TYPE_SECTION) && !(def->type & CFG_TYPE_ARRAY)) {
if (!(cn->v = dm_config_create_value(cft))) {
log_error("Failed to create default config setting node value.");
return NULL;
}
if (spec->withspaces)
format_flags |= DM_CONFIG_VALUE_FMT_COMMON_EXTRA_SPACES;
}
cn->id = def->id;
@@ -1755,6 +1892,9 @@ static struct dm_config_node *_add_def_node(struct dm_config_tree *cft,
if (spec->unconfigured && def->default_unconfigured_value.v_UNCONFIGURED) {
cn->v->type = DM_CFG_STRING;
cn->v->v.str = cfg_def_get_default_unconfigured_value_hint(spec->cmd, def);
if (def->type != CFG_TYPE_STRING)
format_flags |= DM_CONFIG_VALUE_FMT_STRING_NO_QUOTES;
dm_config_value_set_format_flags(cn->v, format_flags);
} else if (!(def->type & CFG_TYPE_ARRAY)) {
switch (def->type) {
case CFG_TYPE_SECTION:
@@ -1767,6 +1907,8 @@ static struct dm_config_node *_add_def_node(struct dm_config_tree *cft,
case CFG_TYPE_INT:
cn->v->type = DM_CFG_INT;
cn->v->v.i = cfg_def_get_default_value_hint(spec->cmd, def, CFG_TYPE_INT, NULL);
if (def->flags & CFG_FORMAT_INT_OCTAL)
format_flags |= DM_CONFIG_VALUE_FMT_INT_OCTAL;
break;
case CFG_TYPE_FLOAT:
cn->v->type = DM_CFG_FLOAT;
@@ -1783,8 +1925,13 @@ static struct dm_config_node *_add_def_node(struct dm_config_tree *cft,
return NULL;
break;
}
} else
cn->v = _get_def_array_values(cft, def);
dm_config_value_set_format_flags(cn->v, format_flags);
} else {
if (spec->withspaces)
format_flags |= DM_CONFIG_VALUE_FMT_COMMON_EXTRA_SPACES;
format_flags |= DM_CONFIG_VALUE_FMT_COMMON_ARRAY;
cn->v = _get_def_array_values(spec->cmd, cft, def, format_flags);
}
cn->child = NULL;
if (parent) {
@@ -1816,6 +1963,8 @@ static int _should_skip_def_node(struct config_def_tree_spec *spec, int section_
return 1;
switch (spec->type) {
case CFG_DEF_TREE_FULL:
/* fall through */
case CFG_DEF_TREE_MISSING:
if (!spec->check_status) {
log_error_once(INTERNAL_ERROR "couldn't determine missing "
@@ -1823,9 +1972,12 @@ static int _should_skip_def_node(struct config_def_tree_spec *spec, int section_
return 1;
}
if ((spec->check_status[id] & CFG_USED) ||
(def->flags & CFG_NAME_VARIABLE) ||
(def->since_version > spec->version) ||
_should_skip_deprecated_def_node(def, spec))
(def->flags & CFG_NAME_VARIABLE))
return 1;
if ((spec->type == CFG_DEF_TREE_MISSING) &&
((def->since_version > spec->version) ||
_should_skip_deprecated_def_node(def, spec)))
return 1;
break;
case CFG_DEF_TREE_NEW:
@@ -1834,7 +1986,9 @@ static int _should_skip_def_node(struct config_def_tree_spec *spec, int section_
return 1;
break;
case CFG_DEF_TREE_PROFILABLE:
/* fall through */
case CFG_DEF_TREE_PROFILABLE_CMD:
/* fall through */
case CFG_DEF_TREE_PROFILABLE_MDA:
if (!(def->flags & CFG_PROFILABLE) ||
(def->since_version > spec->version) ||
@@ -1890,7 +2044,7 @@ bad:
struct dm_config_tree *config_def_create_tree(struct config_def_tree_spec *spec)
{
struct dm_config_tree *cft;
struct dm_config_tree *cft = NULL, *tmp_cft = NULL;
struct dm_config_node *root = NULL, *relay = NULL, *tmp;
int id;
@@ -1914,7 +2068,33 @@ struct dm_config_tree *config_def_create_tree(struct config_def_tree_spec *spec)
}
cft->root = root;
if (spec->type == CFG_DEF_TREE_FULL) {
if (!(tmp_cft = dm_config_create())) {
log_error("Failed to create temporary config tree while creating full tree.");
goto bad;
}
if (!(tmp_cft->root = dm_config_clone_node_with_mem(cft->mem, spec->current_cft->root, 1))) {
log_error("Failed to clone current config tree.");
goto bad;
}
if (!merge_config_tree(spec->cmd, cft, tmp_cft, CONFIG_MERGE_TYPE_RAW)) {
log_error("Failed to merge default and current config tree.");
goto bad;
}
dm_config_destroy(tmp_cft);
}
return cft;
bad:
if (cft)
dm_config_destroy(cft);
if (tmp_cft)
dm_config_destroy(tmp_cft);
return NULL;
}
static int _check_profile(struct cmd_context *cmd, struct profile *profile)

View File

@@ -119,6 +119,10 @@ typedef union {
#define CFG_DEFAULT_RUN_TIME 0x100
/* whether the configuration setting is disabled (and hence defaults always used) */
#define CFG_DISABLED 0x200
/* whether to print integers in octal form (prefixed by "0") */
#define CFG_FORMAT_INT_OCTAL 0x400
/* whether to disable checks for the whole config section subtree */
#define CFG_SECTION_NO_CHECK 0x800
/* configuration definition item structure */
typedef struct cfg_def_item {
@@ -139,7 +143,7 @@ typedef struct cfg_def_item {
typedef enum {
CFG_DEF_TREE_CURRENT, /* tree of nodes with values currently set in the config */
CFG_DEF_TREE_MISSING, /* tree of nodes missing in current config using default values */
CFG_DEF_TREE_COMPLETE, /* CURRENT + MISSING, the tree actually used within execution, not implemented yet */
CFG_DEF_TREE_FULL, /* CURRENT + MISSING, the tree actually used within execution */
CFG_DEF_TREE_DEFAULT, /* tree of all possible config nodes with default values */
CFG_DEF_TREE_NEW, /* tree of all new nodes that appeared in given version */
CFG_DEF_TREE_PROFILABLE, /* tree of all nodes that are customizable by profiles */
@@ -151,18 +155,20 @@ typedef enum {
/* configuration definition tree specification */
struct config_def_tree_spec {
struct cmd_context *cmd; /* command context (for run-time defaults */
cfg_def_tree_t type; /* tree type */
uint16_t version; /* tree at this LVM2 version */
unsigned ignoreadvanced:1; /* do not include advanced configs */
unsigned ignoreunsupported:1; /* do not include unsupported configs */
unsigned ignoredeprecated:1; /* do not include deprecated configs */
unsigned ignorelocal:1; /* do not include the local section */
unsigned withsummary:1; /* include first line of comments - a summary */
unsigned withcomments:1; /* include all comment lines */
unsigned withversions:1; /* include versions */
unsigned unconfigured:1; /* use unconfigured path strings */
uint8_t *check_status; /* status of last tree check (currently needed for CFG_DEF_TREE_MISSING only) */
struct cmd_context *cmd; /* command context (for run-time defaults */
struct dm_config_tree *current_cft; /* current config tree which is defined explicitly - defaults are not used */
cfg_def_tree_t type; /* tree type */
uint16_t version; /* tree at this LVM2 version */
unsigned ignoreadvanced:1; /* do not include advanced configs */
unsigned ignoreunsupported:1; /* do not include unsupported configs */
unsigned ignoredeprecated:1; /* do not include deprecated configs */
unsigned ignorelocal:1; /* do not include the local section */
unsigned withsummary:1; /* include first line of comments - a summary */
unsigned withcomments:1; /* include all comment lines */
unsigned withversions:1; /* include versions */
unsigned withspaces:1; /* add more spaces in output for better readability */
unsigned unconfigured:1; /* use unconfigured path strings */
uint8_t *check_status; /* status of last tree check (currently needed for CFG_DEF_TREE_MISSING only) */
};
@@ -268,6 +274,7 @@ int find_config_tree_int(struct cmd_context *cmd, int id, struct profile *profil
int64_t find_config_tree_int64(struct cmd_context *cmd, int id, struct profile *profile);
float find_config_tree_float(struct cmd_context *cmd, int id, struct profile *profile);
int find_config_tree_bool(struct cmd_context *cmd, int id, struct profile *profile);
const struct dm_config_node *find_config_tree_array(struct cmd_context *cmd, int id, struct profile *profile);
/*
* Functions for configuration settings for which the default

View File

@@ -50,6 +50,8 @@
* CFG_DEFAULT_UNDEFINED - node's default value is undefined (depends on other system/kernel values outside of lvm)
* CFG_DEFAULT_COMMENTED - node's default value is commented out on output
* CFG_DISABLED - configuration is disabled (defaults always used)
* CFG_FORMAT_INT_OCTAL - print integer number in octal form (also prefixed by "0")
* CFG_SECTION_NO_CHECK - do not check content of the section at all - use with care!!!
*
* type: Allowed type for the value of simple configuation setting, one of:
* CFG_TYPE_BOOL
@@ -80,7 +82,7 @@
* (see also lvmconfig ... --withversions)
*
* unconfigured_default_value: Unconfigured default value used as a default value which is
* in "@...@" form and which is then substitued with concrete value
* in "@...@" form and which is then substituted with concrete value
* while running configure.
* (see also 'lvmconfig --type default --unconfigured')
*
@@ -96,12 +98,12 @@
*
* Difference between CFG_DEFAULT_COMMENTED and CFG_DEFAULT_UNDEFINED:
*
* UNDEFINED is only used if the value depends on other
* system/kernel values outside of lvm. The most common
* case is when dm-thin or dm-cache have built-in default
* settings in the kernel, and lvm will use those built-in
* default values unless the corresponding lvm config setting
* is set.
* UNDEFINED is used if default value is NULL or the value
* depends on other system/kernel values outside of lvm.
* The most common case is when dm-thin or dm-cache have
* built-in default settings in the kernel, and lvm will use
* those built-in default values unless the corresponding lvm
* config setting is set.
*
* COMMENTED is used to comment out the default setting in
* lvm.conf. The effect is that if the LVM version is
@@ -202,7 +204,7 @@ cfg(devices_external_device_info_source_CFG, "external_device_info_source", devi
"udev - Reuse existing udev database records. Applicable\n"
"only if LVM is compiled with udev support.\n")
cfg_array(devices_preferred_names_CFG, "preferred_names", devices_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED , CFG_TYPE_STRING, NULL, vsn(1, 2, 19), NULL, 0, NULL,
cfg_array(devices_preferred_names_CFG, "preferred_names", devices_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_UNDEFINED , CFG_TYPE_STRING, NULL, vsn(1, 2, 19), NULL, 0, NULL,
"Select which path name to display for a block device.\n"
"If multiple path names exist for a block device,\n"
"and LVM needs to display a name for the device,\n"
@@ -219,7 +221,7 @@ cfg_array(devices_preferred_names_CFG, "preferred_names", devices_CFG_SECTION, C
"Example:\n"
"preferred_names = [ \"^/dev/mpath/\", \"^/dev/mapper/mpath\", \"^/dev/[hs]d\" ]\n")
cfg_array(devices_filter_CFG, "filter", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL,
cfg_array(devices_filter_CFG, "filter", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, "#Sa|.*/|", vsn(1, 0, 0), NULL, 0, NULL,
"Limit the block devices that are used by LVM commands.\n"
"This is a list of regular expressions used to accept or\n"
"reject block device path names. Each regex is delimited\n"
@@ -249,12 +251,12 @@ cfg_array(devices_filter_CFG, "filter", devices_CFG_SECTION, CFG_DEFAULT_COMMENT
"filter = [ \"a|loop|\", \"r|.*|\" ]\n"
"Example:\n"
"Accept all loop devices and ide drives except hdc.\n"
"filter =[ \"a|loop|\", \"r|/dev/hdc|\", \"a|/dev/ide|\", \"r|.*|\" ]\n"
"filter = [ \"a|loop|\", \"r|/dev/hdc|\", \"a|/dev/ide|\", \"r|.*|\" ]\n"
"Example:\n"
"Use anchors to be very specific.\n"
"filter = [ \"a|^/dev/hda8$|\", \"r|.*/|\" ]\n")
cfg_array(devices_global_filter_CFG, "global_filter", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, NULL, vsn(2, 2, 98), NULL, 0, NULL,
cfg_array(devices_global_filter_CFG, "global_filter", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, "#Sa|.*/|", vsn(2, 2, 98), NULL, 0, NULL,
"Limit the block devices that are used by LVM system components.\n"
"Because devices/filter may be overridden from the command line,\n"
"it is not suitable for system-wide device filtering, e.g. udev\n"
@@ -281,7 +283,7 @@ cfg(devices_cache_file_prefix_CFG, "cache_file_prefix", devices_CFG_SECTION, CFG
cfg(devices_write_cache_state_CFG, "write_cache_state", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, 1, vsn(1, 0, 0), NULL, 0, NULL,
"Enable/disable writing the cache file. See devices/cache_dir.\n")
cfg_array(devices_types_CFG, "types", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED| CFG_ADVANCED, CFG_TYPE_INT | CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL,
cfg_array(devices_types_CFG, "types", devices_CFG_SECTION, CFG_DEFAULT_UNDEFINED | CFG_ADVANCED, CFG_TYPE_INT | CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL,
"List of additional acceptable block device types.\n"
"These are of device type names from /proc/devices,\n"
"followed by the maximum number of partitions.\n"
@@ -398,7 +400,7 @@ cfg(devices_issue_discards_CFG, "issue_discards", devices_CFG_SECTION, 0, CFG_TY
"and thinly provisioned LUNs generally do. If enabled, discards\n"
"will only be issued if both the storage and kernel provide support.\n")
cfg_array(allocation_cling_tag_list_CFG, "cling_tag_list", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, NULL, vsn(2, 2, 77), NULL, 0, NULL,
cfg_array(allocation_cling_tag_list_CFG, "cling_tag_list", allocation_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 2, 77), NULL, 0, NULL,
"Advise LVM which PVs to use when searching for new space.\n"
"When searching for free space to extend an LV, the 'cling'\n"
"allocation policy will choose space on the same PVs as the last\n"
@@ -422,7 +424,7 @@ cfg(allocation_maximise_cling_CFG, "maximise_cling", allocation_CFG_SECTION, 0,
"the same disks. This setting can be used to disable the changes\n"
"and revert to the previous algorithm.\n")
cfg(allocation_use_blkid_wiping_CFG, "use_blkid_wiping", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, 1, vsn(2, 2, 105), NULL, 0, NULL,
cfg(allocation_use_blkid_wiping_CFG, "use_blkid_wiping", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, 1, vsn(2, 2, 105), "@DEFAULT_USE_BLKID_WIPING@", 0, NULL,
"Use blkid to detect existing signatures on new PVs and LVs.\n"
"The blkid library can detect more signatures than the\n"
"native LVM detection code, but may take longer.\n"
@@ -532,7 +534,7 @@ cfg(log_silent_CFG, "silent", log_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_SILENT,
cfg(log_syslog_CFG, "syslog", log_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_SYSLOG, vsn(1, 0, 0), NULL, 0, NULL,
"Send log messages through syslog.\n")
cfg(log_file_CFG, "file", log_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL,
cfg(log_file_CFG, "file", log_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL,
"Write error and debug log messages to a file specified here.\n")
cfg(log_overwrite_CFG, "overwrite", log_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_OVERWRITE, vsn(1, 0, 0), NULL, 0, NULL,
@@ -560,7 +562,7 @@ cfg(log_activation_CFG, "activation", log_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(
"Log messages during activation.\n"
"Don't use this in low memory situations (can deadlock).\n")
cfg(log_activate_file_CFG, "activate_file", log_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_UNSUPPORTED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL, NULL)
cfg(log_activate_file_CFG, "activate_file", log_CFG_SECTION, CFG_DEFAULT_UNDEFINED | CFG_UNSUPPORTED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL, NULL)
cfg_array(log_debug_classes_CFG, "debug_classes", log_CFG_SECTION, CFG_ALLOW_EMPTY, CFG_TYPE_STRING, "#Smemory#Sdevices#Sactivation#Sallocation#Slvmetad#Smetadata#Scache#Slocking#Slvmpolld", vsn(2, 2, 99), NULL, 0, NULL,
"Select log messages by class.\n"
@@ -596,7 +598,7 @@ cfg(backup_retain_days_CFG, "retain_days", backup_CFG_SECTION, 0, CFG_TYPE_INT,
cfg(shell_history_size_CFG, "history_size", shell_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_MAX_HISTORY, vsn(1, 0, 0), NULL, 0, NULL,
"Number of lines of history to store in ~/.lvm_history.\n")
cfg(global_umask_CFG, "umask", global_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_UMASK, vsn(1, 0, 0), NULL, 0, NULL,
cfg(global_umask_CFG, "umask", global_CFG_SECTION, CFG_FORMAT_INT_OCTAL, CFG_TYPE_INT, DEFAULT_UMASK, vsn(1, 0, 0), NULL, 0, NULL,
"The file creation mask for any files and directories created.\n"
"Interpreted as octal if the first digit is zero.\n")
@@ -617,7 +619,7 @@ cfg(global_si_unit_consistency_CFG, "si_unit_consistency", global_CFG_SECTION, C
cfg(global_suffix_CFG, "suffix", global_CFG_SECTION, CFG_PROFILABLE, CFG_TYPE_BOOL, DEFAULT_SUFFIX, vsn(1, 0, 0), NULL, 0, NULL,
"Display unit suffix for sizes.\n"
"This setting has no effect if the units are in human-readable\n"
"form (global/units=\"h\") in which case the suffix is always\n"
"form (global/units = \"h\") in which case the suffix is always\n"
"displayed.\n")
cfg(global_activation_CFG, "activation", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_ACTIVATION, vsn(1, 0, 0), NULL, 0, NULL,
@@ -627,7 +629,7 @@ cfg(global_activation_CFG, "activation", global_CFG_SECTION, 0, CFG_TYPE_BOOL, D
"is not present in the kernel, disabling this should suppress\n"
"the error messages.\n")
cfg(global_fallback_to_lvm1_CFG, "fallback_to_lvm1", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_FALLBACK_TO_LVM1, vsn(1, 0, 18), NULL, 0, NULL,
cfg(global_fallback_to_lvm1_CFG, "fallback_to_lvm1", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_FALLBACK_TO_LVM1, vsn(1, 0, 18), "@DEFAULT_FALLBACK_TO_LVM1@", 0, NULL,
"Try running LVM1 tools if LVM cannot communicate with DM.\n"
"This option only applies to 2.4 kernels and is provided to\n"
"help switch between device-mapper kernels and LVM1 kernels.\n"
@@ -640,12 +642,12 @@ cfg(global_format_CFG, "format", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_
"\"lvm1\" or \"lvm2\".\n"
"The command line override is -M1 or -M2.\n")
cfg_array(global_format_libraries_CFG, "format_libraries", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL,
cfg_array(global_format_libraries_CFG, "format_libraries", global_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL,
"Shared libraries that process different metadata formats.\n"
"If support for LVM1 metadata was compiled as a shared library use\n"
"format_libraries = \"liblvm2format1.so\"\n")
cfg_array(global_segment_libraries_CFG, "segment_libraries", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, NULL, vsn(1, 0, 18), NULL, 0, NULL, NULL)
cfg_array(global_segment_libraries_CFG, "segment_libraries", global_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 18), NULL, 0, NULL, NULL)
cfg(global_proc_CFG, "proc", global_CFG_SECTION, CFG_ADVANCED, CFG_TYPE_STRING, DEFAULT_PROC_DIR, vsn(1, 0, 0), NULL, 0, NULL,
"Location of proc filesystem.\n")
@@ -710,7 +712,7 @@ cfg(global_prioritise_write_locks_CFG, "prioritise_write_locks", global_CFG_SECT
"This option only affects locking_type 1 viz.\n"
"local file-based locking.\n")
cfg(global_library_dir_CFG, "library_dir", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL,
cfg(global_library_dir_CFG, "library_dir", global_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL,
"Search this directory first for shared libraries.\n")
cfg(global_locking_library_CFG, "locking_library", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_LOCKING_LIB, vsn(1, 0, 0), NULL, 0, NULL,
@@ -796,7 +798,7 @@ cfg(global_lvdisplay_shows_full_device_path_CFG, "lvdisplay_shows_full_device_pa
"was never a valid path in the /dev filesystem.\n"
"Enable this option to reinstate the previous format.\n")
cfg(global_use_lvmetad_CFG, "use_lvmetad", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_USE_LVMETAD, vsn(2, 2, 93), NULL, 0, NULL,
cfg(global_use_lvmetad_CFG, "use_lvmetad", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_USE_LVMETAD, vsn(2, 2, 93), "@DEFAULT_USE_LVMETAD@", 0, NULL,
"Use lvmetad to cache metadata and reduce disk scanning.\n"
"When enabled (and running), lvmetad provides LVM commands\n"
"with VG metadata and PV state. LVM commands then avoid\n"
@@ -830,6 +832,20 @@ cfg(global_use_lvmetad_CFG, "use_lvmetad", global_CFG_SECTION, 0, CFG_TYPE_BOOL,
"LVM prints warnings and ignores lvmetad if this combination\n"
"is seen.\n")
cfg(global_use_lvmlockd_CFG, "use_lvmlockd", global_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(2, 2, 124), NULL, 0, NULL,
"Use lvmlockd for locking among hosts using LVM on shared storage.\n")
cfg(global_lvmlockd_lock_retries_CFG, "lvmlockd_lock_retries", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_LVMLOCKD_LOCK_RETRIES, vsn(2, 2, 125), NULL, 0, NULL,
"Retry lvmlockd lock requests this many times.\n")
cfg(global_sanlock_lv_extend_CFG, "sanlock_lv_extend", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_SANLOCK_LV_EXTEND_MB, vsn(2, 2, 124), NULL, 0, NULL,
"Size in MiB to extend the internal LV holding sanlock locks.\n"
"The internal LV holds locks for each LV in the VG, and after\n"
"enough LVs have been created, the internal LV needs to be extended.\n"
"lvcreate will automatically extend the internal LV when needed by\n"
"the amount specified here. Setting this to 0 disables the\n"
"automatic extension and can cause lvcreate to fail.\n")
cfg(global_thin_check_executable_CFG, "thin_check_executable", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, THIN_CHECK_CMD, vsn(2, 2, 94), "@THIN_CHECK_CMD@", 0, NULL,
"The full path to the thin_check command.\n"
"LVM uses this command to check that a thin metadata\n"
@@ -854,7 +870,7 @@ cfg(global_thin_repair_executable_CFG, "thin_repair_executable", global_CFG_SECT
"Also see thin_repair_options.\n"
"(For thin tools, see thin_check_executable.)\n")
cfg_array(global_thin_check_options_CFG, "thin_check_options", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, "#S" DEFAULT_THIN_CHECK_OPTION1 "#S" DEFAULT_THIN_CHECK_OPTION2, vsn(2, 2, 96), NULL, 0, NULL,
cfg_array(global_thin_check_options_CFG, "thin_check_options", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_THIN_CHECK_OPTIONS_CONFIG, vsn(2, 2, 96), NULL, 0, NULL,
"List of options passed to the thin_check command.\n"
"With thin_check version 2.1 or newer you can add\n"
"--ignore-non-fatal-errors to let it pass through\n"
@@ -862,10 +878,10 @@ cfg_array(global_thin_check_options_CFG, "thin_check_options", global_CFG_SECTIO
"With thin_check version 3.2 or newer you should add\n"
"--clear-needs-check-flag.\n")
cfg_array(global_thin_repair_options_CFG, "thin_repair_options", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, "#S" DEFAULT_THIN_REPAIR_OPTIONS, vsn(2, 2, 100), NULL, 0, NULL,
cfg_array(global_thin_repair_options_CFG, "thin_repair_options", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_THIN_REPAIR_OPTIONS_CONFIG, vsn(2, 2, 100), NULL, 0, NULL,
"List of options passed to the thin_repair command.\n")
cfg_array(global_thin_disabled_features_CFG, "thin_disabled_features", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, NULL, vsn(2, 2, 99), NULL, 0, NULL,
cfg_array(global_thin_disabled_features_CFG, "thin_disabled_features", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 2, 99), NULL, 0, NULL,
"Features to not use in the thin driver.\n"
"This can be helpful for testing, or to avoid\n"
"using a feature that is causing problems.\n"
@@ -885,7 +901,9 @@ cfg(global_cache_check_executable_CFG, "cache_check_executable", global_CFG_SECT
"Set to \"\" to skip this check. (Not recommended.)\n"
"Also see cache_check_options.\n"
"The cache tools are available from the package\n"
"device-mapper-persistent-data.\n")
"device-mapper-persistent-data.\n"
"With cache_check version 5.0 or newer you should add\n"
"--clear-needs-check-flag.\n")
cfg(global_cache_dump_executable_CFG, "cache_dump_executable", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, CACHE_DUMP_CMD, vsn(2, 2, 108), "@CACHE_DUMP_CMD@", 0, NULL,
"The full path to the cache_dump command.\n"
@@ -899,10 +917,10 @@ cfg(global_cache_repair_executable_CFG, "cache_repair_executable", global_CFG_SE
"Also see cache_repair_options.\n"
"(For cache tools, see cache_check_executable.)\n")
cfg_array(global_cache_check_options_CFG, "cache_check_options", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, "#S" DEFAULT_CACHE_CHECK_OPTION1, vsn(2, 2, 108), NULL, 0, NULL,
cfg_array(global_cache_check_options_CFG, "cache_check_options", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_CACHE_CHECK_OPTIONS_CONFIG, vsn(2, 2, 108), NULL, 0, NULL,
"List of options passed to the cache_check command.\n")
cfg_array(global_cache_repair_options_CFG, "cache_repair_options", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, "#S" DEFAULT_CACHE_REPAIR_OPTIONS, vsn(2, 2, 108), NULL, 0, NULL,
cfg_array(global_cache_repair_options_CFG, "cache_repair_options", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_CACHE_REPAIR_OPTIONS_CONFIG, vsn(2, 2, 108), NULL, 0, NULL,
"List of options passed to the cache_repair command.\n")
cfg(global_system_id_source_CFG, "system_id_source", global_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_SYSTEM_ID_SOURCE, vsn(2, 2, 117), NULL, 0, NULL,
@@ -925,7 +943,7 @@ cfg(global_system_id_source_CFG, "system_id_source", global_CFG_SECTION, 0, CFG_
"file - Use the contents of another file (system_id_file) to set\n"
"the system ID.\n")
cfg(global_system_id_file_CFG, "system_id_file", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, NULL, vsn(2, 2, 117), NULL, 0, NULL,
cfg(global_system_id_file_CFG, "system_id_file", global_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 2, 117), NULL, 0, NULL,
"The full path to the file containing a system ID.\n"
"This is used when system_id_source is set to 'file'.\n"
"Comments starting with the character # are ignored.\n")
@@ -936,7 +954,7 @@ cfg(activation_checks_CFG, "checks", activation_CFG_SECTION, 0, CFG_TYPE_BOOL, D
"Some of the checks may be expensive, so it's best to use\n"
"this only when there seems to be a problem.\n")
cfg(global_use_lvmpolld_CFG, "use_lvmpolld", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_USE_LVMPOLLD, vsn(2, 2, 120), NULL, 0, NULL,
cfg(global_use_lvmpolld_CFG, "use_lvmpolld", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_USE_LVMPOLLD, vsn(2, 2, 120), "@DEFAULT_USE_LVMPOLLD@", 0, NULL,
"Use lvmpolld to supervise long running LVM commands.\n"
"When enabled, control of long running LVM commands is transferred\n"
"from the original LVM command to the lvmpolld daemon. This allows\n"
@@ -1007,7 +1025,7 @@ cfg(activation_process_priority_CFG, "process_priority", activation_CFG_SECTION,
"Use a high priority so that LVs are suspended\n"
"for the shortest possible time.\n")
cfg_array(activation_volume_list_CFG, "volume_list", activation_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, NULL, vsn(1, 0, 18), NULL, 0, NULL,
cfg_array(activation_volume_list_CFG, "volume_list", activation_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 18), NULL, 0, NULL,
"Only LVs selected by this list are activated.\n"
"If this list is defined, an LV is only activated\n"
"if it matches an entry in this list.\n"
@@ -1024,7 +1042,7 @@ cfg_array(activation_volume_list_CFG, "volume_list", activation_CFG_SECTION, CFG
"Example:\n"
"volume_list = [ \"vg1\", \"vg2/lvol1\", \"@tag1\", \"@*\" ]\n")
cfg_array(activation_auto_activation_volume_list_CFG, "auto_activation_volume_list", activation_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, NULL, vsn(2, 2, 97), NULL, 0, NULL,
cfg_array(activation_auto_activation_volume_list_CFG, "auto_activation_volume_list", activation_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 2, 97), NULL, 0, NULL,
"Only LVs selected by this list are auto-activated.\n"
"This list works like volume_list, but it is used\n"
"only by auto-activation commands. It does not apply\n"
@@ -1054,7 +1072,7 @@ cfg_array(activation_auto_activation_volume_list_CFG, "auto_activation_volume_li
"Possible options are: vgname, vgname/lvname, @tag, @*\n"
"See volume_list for how these options are matched to LVs.\n")
cfg_array(activation_read_only_volume_list_CFG, "read_only_volume_list", activation_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, NULL, vsn(2, 2, 89), NULL, 0, NULL,
cfg_array(activation_read_only_volume_list_CFG, "read_only_volume_list", activation_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 2, 89), NULL, 0, NULL,
"LVs in this list are activated in read-only mode.\n"
"If this list is defined, each LV that is to be activated\n"
"is checked against this list, and if it matches, it is\n"
@@ -1191,7 +1209,7 @@ cfg(activation_thin_pool_autoextend_percent_CFG, "thin_pool_autoextend_percent",
"The amount of additional space added to a thin pool is this\n"
"percent of its current size.\n")
cfg_array(activation_mlock_filter_CFG, "mlock_filter", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_ADVANCED, CFG_TYPE_STRING, NULL, vsn(2, 2, 62), NULL, 0, NULL,
cfg_array(activation_mlock_filter_CFG, "mlock_filter", activation_CFG_SECTION, CFG_DEFAULT_UNDEFINED | CFG_ADVANCED, CFG_TYPE_STRING, NULL, vsn(2, 2, 62), NULL, 0, NULL,
"Do not mlock these memory areas.\n"
"While activating devices, I/O to devices being\n"
"(re)configured is suspended. As a precaution against\n"
@@ -1205,7 +1223,7 @@ cfg_array(activation_mlock_filter_CFG, "mlock_filter", activation_CFG_SECTION, C
"locale-archive was found to make up over 80% of the memory\n"
"used by the process.\n"
"Example:\n"
"mlock_filter=[ \"locale/locale-archive\", \"gconv/gconv-modules.cache\" ]\n")
"mlock_filter = [ \"locale/locale-archive\", \"gconv/gconv-modules.cache\" ]\n")
cfg(activation_use_mlockall_CFG, "use_mlockall", activation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_USE_MLOCKALL, vsn(2, 2, 62), NULL, 0, NULL,
"Use the old behavior of mlockall to pin all memory.\n"
@@ -1255,6 +1273,14 @@ cfg(activation_mode_CFG, "activation_mode", activation_CFG_SECTION, 0, CFG_TYPE_
"sometimes assist with data recovery.\n"
"The '--activationmode' option overrides this setting.\n")
cfg_array(activation_lock_start_list_CFG, "lock_start_list", activation_CFG_SECTION, CFG_ALLOW_EMPTY|CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 2, 124), NULL, 0, NULL,
"Locking is started only for VGs selected by this list.\n"
"The rules are the same as those for LVs in volume_list.\n")
cfg_array(activation_auto_lock_start_list_CFG, "auto_lock_start_list", activation_CFG_SECTION, CFG_ALLOW_EMPTY|CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 2, 124), NULL, 0, NULL,
"Locking is auto-started only for VGs selected by this list.\n"
"The rules are the same as those for LVs in auto_activation_volume_list.\n")
cfg(metadata_pvmetadatacopies_CFG, "pvmetadatacopies", metadata_CFG_SECTION, CFG_ADVANCED | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_PVMETADATACOPIES, vsn(1, 0, 0), NULL, 0, NULL,
"Number of copies of metadata to store on each PV.\n"
"Possible options are: 0, 1, 2.\n"
@@ -1293,7 +1319,7 @@ cfg(metadata_pvmetadataignore_CFG, "pvmetadataignore", metadata_CFG_SECTION, CFG
cfg(metadata_stripesize_CFG, "stripesize", metadata_CFG_SECTION, CFG_ADVANCED | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_STRIPESIZE, vsn(1, 0, 0), NULL, 0, NULL, NULL)
cfg_array(metadata_dirs_CFG, "dirs", metadata_CFG_SECTION, CFG_ADVANCED | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL,
cfg_array(metadata_dirs_CFG, "dirs", metadata_CFG_SECTION, CFG_ADVANCED | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL,
"Directories holding live copies of text format metadata.\n"
"These directories must not be on logical volumes!\n"
"It's possible to use LVM with a couple of directories here,\n"
@@ -1312,7 +1338,7 @@ cfg_section(metadata_disk_areas_CFG_SUBSECTION, "disk_areas", metadata_CFG_SECTI
cfg_section(disk_area_CFG_SUBSECTION, "disk_area", metadata_disk_areas_CFG_SUBSECTION, CFG_NAME_VARIABLE | CFG_UNSUPPORTED | CFG_DEFAULT_COMMENTED, vsn(1, 0, 0), 0, NULL, NULL)
cfg(disk_area_start_sector_CFG, "start_sector", disk_area_CFG_SUBSECTION, CFG_UNSUPPORTED | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, 0, vsn(1, 0, 0), NULL, 0, NULL, NULL)
cfg(disk_area_size_CFG, "size", disk_area_CFG_SUBSECTION, CFG_UNSUPPORTED | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, 0, vsn(1, 0, 0), NULL, 0, NULL, NULL)
cfg(disk_area_id_CFG, "id", disk_area_CFG_SUBSECTION, CFG_UNSUPPORTED | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL, NULL)
cfg(disk_area_id_CFG, "id", disk_area_CFG_SUBSECTION, CFG_UNSUPPORTED | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL, NULL)
cfg(report_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"
@@ -1356,6 +1382,79 @@ cfg(report_binary_values_as_numeric_CFG, "binary_values_as_numeric", report_CFG_
"(not counting the 'unknown' value which denotes that the\n"
"value could not be determined).\n")
cfg(report_time_format_CFG, "time_format", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_TIME_FORMAT, vsn(2, 2, 123), NULL, 0, NULL,
"Set time format for fields reporting time values.\n"
"Format specification is a string which may contain special character\n"
"sequences and ordinary character sequences. Ordinary character sequences\n"
"are copied verbatim. Each special character sequence is introduced by \'%\'\n"
"character and such sequence is then substituted with a value as described below:\n"
"\%a The abbreviated name of the day of the week according to the\n"
" current locale.\n"
"\%A The full name of the day of the week according to the current locale.\n"
"\%b The abbreviated month name according to the current locale.\n"
"\%B The full month name according to the current locale.\n"
"\%c The preferred date and time representation for the current locale. (alt E)\n"
"\%C The century number (year/100) as a 2-digit integer. (alt E)\n"
"\%d The day of the month as a decimal number (range 01 to 31). (alt O)\n"
"\%D Equivalent to \%m/\%d/\%y. (For Americans only. Americans should\n"
" note that in other countries\%d/\%m/\%y is rather common. This means\n"
" that in international context this format is ambiguous and should not\n"
" be used.\n"
"\%e Like \%d, the day of the month as a decimal number, but a leading zero\n"
" is replaced by a space. (alt O)\n"
"\%E Modifier: use alternative local-dependent representation if available.\n"
"\%F Equivalent to \%Y-\%m-\%d (the ISO 8601 date format).\n"
"\%G The ISO 8601 week-based year with century as adecimal number. The 4-digit\n"
" year corresponding to the ISO week number (see \%V). This has the same\n"
" format and value as \%Y, except that if the ISO week number belongs to\n"
" the previous or next year, that year is used instead.\n"
"\%g Like \%G, but without century, that is, with a 2-digit year (00-99).\n"
"\%h Equivalent to \%b.\n"
"\%H The hour as a decimal number using a 24-hour clock (range 00 to 23). (alt O)\n"
"\%I The hour as a decimal number using a 12-hour clock (range 01 to 12). (alt O)\n"
"\%j The day of the year as a decimal number (range 001 to 366).\n"
"\%k The hour (24-hour clock) as a decimal number (range 0 to 23);\n"
" single digits are preceded by a blank. (See also \%H.)\n"
"\%l The hour (12-hour clock) as a decimal number (range 1 to 12);\n"
" single digits are preceded by a blank. (See also \%I.)\n"
"\%m The month as a decimal number (range 01 to 12). (alt O)\n"
"\%M The minute as a decimal number (range 00 to 59). (alt O)\n"
"\%O Modifier: use alternative numeric symbols.\n"
"\%p Either \"AM\" or \"PM\" according to the given time value,\n"
" or the corresponding strings for the current locale. Noon is\n"
" treated as \"PM\" and midnight as \"AM\".\n"
"\%P Like \%p but in lowercase: \"am\" or \"pm\" or a corresponding\n"
" string for the current locale.\n"
"\%r The time in a.m. or p.m. notation. In the POSIX locale this is\n"
" equivalent to \%I:\%M:\%S \%p.\n"
"\%R The time in 24-hour notation (\%H:\%M). For a version including\n"
" the seconds, see \%T below.\n"
"\%s The number of seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC)\n"
"\%S The second as a decimal number (range 00 to 60).\n"
" (The range is up to 60 to allow for occasional leap seconds.) (alt O)\n"
"\%t A tab character.\n"
"\%T The time in 24-hour notation (\%H:\%M:\%S).\n"
"\%u The day of the week as a decimal, range 1 to 7, Monday being 1.\n"
" See also \%w. (alt O)\n"
"\%U The week number of the current year as a decimal number,\n"
" range 00 to 53, starting with the first Sunday as the first\n"
" day of week 01. See also \%V and \%W. (alt O)\n"
"\%V The ISO 8601 week number of the current year as a decimal number,\n"
" range 01 to 53, where week 1 is the first week that has at least 4 days\n"
" in the new year. See also \%U and \%W. (alt O)\n"
"\%w The day of the week as a decimal, range 0 to 6, Sunday being 0.\n"
" See also \%u. (alt O)\n"
"\%W The week number of the current year as a decimal number, range 00 to 53,\n"
" starting with the first Monday as the first day of week 01. (alt O)\n"
"\%x The preferred date representation for the current locale without the time. (alt E)\n"
"\%X The preferred time representation for the current locale without the date. (alt E)\n"
"\%y The year as a decimal number without a century (range 00 to 99). (alt E, alt O)\n"
"\%Y The year as a decimal number including the century. (alt E)\n"
"\%z The +hhmm or -hhmm numeric timezone (that is, the hour and minute\n"
" offset from UTC).\n"
"\%Z The timezone name or abbreviation.\n"
"\%\% A literal '\%' character.\n")
cfg(report_devtypes_sort_CFG, "devtypes_sort", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_DEVTYPES_SORT, vsn(2, 2, 101), NULL, 0, NULL,
"List of columns to sort by when reporting 'lvm devtypes' command.\n"
"See 'lvm devtypes -o help' for the list of possible fields.\n")
@@ -1474,7 +1573,7 @@ cfg_section(tag_CFG_SUBSECTION, "tag", tags_CFG_SECTION, CFG_NAME_VARIABLE | CFG
"bar is given to the hosts named machine1 and machine2.\n"
"tags { foo { } bar { host_list = [ \"machine1\", \"machine2\" ] } }\n")
cfg_array(tag_host_list_CFG, "host_list", tag_CFG_SUBSECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, NULL, vsn(1, 0, 18), NULL, 0, NULL,
cfg_array(tag_host_list_CFG, "host_list", tag_CFG_SUBSECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 18), NULL, 0, NULL,
"A list of machine names.\n"
"These machine names are compared to the nodename\n"
"returned by uname(2). If the local machine name\n"
@@ -1496,7 +1595,7 @@ cfg(local_system_id_CFG, "system_id", local_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_D
"Set the system_id to the string 'host1'.\n"
"system_id = \"host1\"\n")
cfg_array(local_extra_system_ids_CFG, "extra_system_ids", local_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, NULL, vsn(2, 2, 117), NULL, 0, NULL,
cfg_array(local_extra_system_ids_CFG, "extra_system_ids", local_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 2, 117), NULL, 0, NULL,
"A list of extra VG system IDs the local host can access.\n"
"VGs with the system IDs listed here (in addition\n"
"to the host's own system ID) can be fully accessed\n"
@@ -1506,4 +1605,9 @@ cfg_array(local_extra_system_ids_CFG, "extra_system_ids", local_CFG_SECTION, CFG
"Use this only after consulting 'man lvmsystemid'\n"
"to be certain of correct usage and possible dangers.\n")
cfg(local_host_id_CFG, "host_id", local_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, 0, vsn(2, 2, 124), NULL, 0, NULL,
"The lvmlockd sanlock host_id.\n"
"This must be a unique among all hosts,\n"
"and must be between 1 and 2000.\n")
cfg(CFG_COUNT, NULL, root_CFG_SECTION, 0, CFG_TYPE_INT, 0, vsn(0, 0, 0), NULL, 0, NULL, NULL)

View File

@@ -51,11 +51,14 @@
#define DEFAULT_FALLBACK_TO_LOCAL_LOCKING 1
#define DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING 1
#define DEFAULT_WAIT_FOR_LOCKS 1
#define DEFAULT_LVMLOCKD_LOCK_RETRIES 3
#define DEFAULT_PRIORITISE_WRITE_LOCKS 1
#define DEFAULT_USE_MLOCKALL 0
#define DEFAULT_METADATA_READ_ONLY 0
#define DEFAULT_LVDISPLAY_SHOWS_FULL_DEVICE_PATH 0
#define DEFAULT_SANLOCK_LV_EXTEND_MB 256
#define DEFAULT_MIRRORLOG MIRROR_LOG_DISK
#define DEFAULT_MIRROR_LOG_FAULT_POLICY "allocate"
#define DEFAULT_MIRROR_IMAGE_FAULT_POLICY "remove"
@@ -78,12 +81,15 @@
#ifdef THIN_CHECK_NEEDS_CHECK
# define DEFAULT_THIN_CHECK_OPTION1 "-q"
# define DEFAULT_THIN_CHECK_OPTION2 "--clear-needs-check-flag"
# define DEFAULT_THIN_CHECK_OPTIONS_CONFIG "#S" DEFAULT_THIN_CHECK_OPTION1 "#S" DEFAULT_THIN_CHECK_OPTION2
#else
# define DEFAULT_THIN_CHECK_OPTION1 "-q"
# define DEFAULT_THIN_CHECK_OPTION2 ""
# define DEFAULT_THIN_CHECK_OPTIONS_CONFIG "#S" DEFAULT_THIN_CHECK_OPTION1
#endif
#define DEFAULT_THIN_REPAIR_OPTIONS ""
#define DEFAULT_THIN_REPAIR_OPTION1 ""
#define DEFAULT_THIN_REPAIR_OPTIONS_CONFIG "#S" DEFAULT_THIN_REPAIR_OPTION1
#define DEFAULT_THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS 0
#define DEFAULT_THIN_POOL_MAX_METADATA_SIZE (16 * 1024 * 1024) /* KB */
#define DEFAULT_THIN_POOL_MIN_METADATA_SIZE 2048 /* KB */
@@ -95,8 +101,18 @@
#define DEFAULT_THIN_POOL_ZERO 1
#define DEFAULT_POOL_METADATA_SPARE 1 /* thin + cache */
#define DEFAULT_CACHE_CHECK_OPTION1 "-q"
#define DEFAULT_CACHE_REPAIR_OPTIONS ""
#ifdef CACHE_CHECK_NEEDS_CHECK
# define DEFAULT_CACHE_CHECK_OPTION1 "-q"
# define DEFAULT_CACHE_CHECK_OPTION2 "--clear-needs-check-flag"
# define DEFAULT_CACHE_CHECK_OPTIONS_CONFIG "#S" DEFAULT_CACHE_CHECK_OPTION1 "#S" DEFAULT_CACHE_CHECK_OPTION2
#else
# define DEFAULT_CACHE_CHECK_OPTION1 "-q"
# define DEFAULT_CACHE_CHECK_OPTION2 ""
# define DEFAULT_CACHE_CHECK_OPTIONS_CONFIG "#S" DEFAULT_CACHE_CHECK_OPTION1
#endif
#define DEFAULT_CACHE_REPAIR_OPTION1 ""
#define DEFAULT_CACHE_REPAIR_OPTIONS_CONFIG "#S" DEFAULT_CACHE_REPAIR_OPTION1
#define DEFAULT_CACHE_POOL_METADATA_REQUIRE_SEPARATE_PVS 0
#define DEFAULT_CACHE_POOL_CHUNK_SIZE 64 /* KB */
#define DEFAULT_CACHE_POOL_MIN_METADATA_SIZE 2048 /* KB */
@@ -106,12 +122,6 @@
#define DEFAULT_UMASK 0077
#ifdef LVM1_FALLBACK
# define DEFAULT_FALLBACK_TO_LVM1 1
#else
# define DEFAULT_FALLBACK_TO_LVM1 0
#endif
#define DEFAULT_FORMAT "lvm2"
#define DEFAULT_STRIPESIZE 64 /* KB */
@@ -142,11 +152,6 @@
# define DEFAULT_LOG_FACILITY LOG_USER
#endif
#define DEFAULT_LOGGED_DEBUG_CLASSES (LOG_CLASS_MEM | LOG_CLASS_DEVS | \
LOG_CLASS_ACTIVATION | LOG_CLASS_ALLOC | LOG_CLASS_LVMETAD | \
LOG_CLASS_METADATA | LOG_CLASS_CACHE | LOG_CLASS_LOCKING | \
LOG_CLASS_LVMPOLLD)
#define DEFAULT_SYSLOG 1
#define DEFAULT_VERBOSE 0
#define DEFAULT_SILENT 0
@@ -192,6 +197,7 @@
#define DEFAULT_REP_QUOTED 1
#define DEFAULT_REP_SEPARATOR " "
#define DEFAULT_REP_LIST_ITEM_SEPARATOR ","
#define DEFAULT_TIME_FORMAT "%Y-%m-%d %T %z"
#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"
@@ -221,4 +227,6 @@
#define DEFAULT_THIN_POOL_AUTOEXTEND_THRESHOLD 100
#define DEFAULT_THIN_POOL_AUTOEXTEND_PERCENT 20
#define DEFAULT_CY_LOCK_TYPE "sanlock"
#endif /* _LVM_DEFAULTS_H */

View File

@@ -681,10 +681,12 @@ static int _init_preferred_names(struct cmd_context *cmd)
_cache.preferred_names_matcher = NULL;
if (!(cn = find_config_tree_node(cmd, devices_preferred_names_CFG, NULL)) ||
if (!(cn = find_config_tree_array(cmd, devices_preferred_names_CFG, NULL)) ||
cn->v->type == DM_CFG_EMPTY_ARRAY) {
log_very_verbose("devices/preferred_names not found in config file: "
"using built-in preferences");
log_very_verbose("devices/preferred_names %s: "
"using built-in preferences",
cn && cn->v->type == DM_CFG_EMPTY_ARRAY ? "is empty"
: "not found in config");
return 1;
}
@@ -943,7 +945,7 @@ struct device *dev_cache_get(const char *name, struct dev_filter *f)
if (d)
dm_hash_remove(_cache.names, name);
log_sys_very_verbose("stat", name);
return NULL;
d = NULL;
}
if (d && (buf.st_rdev != d->dev)) {

View File

@@ -528,12 +528,14 @@ static inline int _type_in_flag_list(const char *type, uint32_t flag_list)
((flag_list & TYPE_DM_SNAPSHOT_COW) && !strcmp(type, "DM_snapshot_cow")));
}
#define MSG_FAILED_SIG_OFFSET "Failed to get offset of the %s signature on %s."
#define MSG_FAILED_SIG_LENGTH "Failed to get length of the %s signature on %s."
#define MSG_WIPING_SKIPPED " Wiping skipped."
static int _blkid_wipe(blkid_probe probe, struct device *dev, const char *name,
uint32_t types_to_exclude, uint32_t types_no_prompt,
int yes, force_t force)
{
static const char _msg_failed_offset[] = "Failed to get offset of the %s signature on %s.";
static const char _msg_failed_length[] = "Failed to get length of the %s signature on %s.";
static const char _msg_wiping[] = "Wiping %s signature on %s.";
const char *offset = NULL, *type = NULL, *magic = NULL,
*usage = NULL, *label = NULL, *uuid = NULL;
@@ -544,21 +546,41 @@ static int _blkid_wipe(blkid_probe probe, struct device *dev, const char *name,
if (_type_in_flag_list(type, types_to_exclude))
return 2;
if (blkid_probe_lookup_value(probe, "SBMAGIC_OFFSET", &offset, NULL)) {
log_error(_msg_failed_offset, type, name);
return 0;
if (force < DONT_PROMPT) {
log_error(MSG_FAILED_SIG_OFFSET, type, name);
return 0;
} else {
log_error("WARNING: " MSG_FAILED_SIG_OFFSET MSG_WIPING_SKIPPED, type, name);
return 2;
}
}
if (blkid_probe_lookup_value(probe, "SBMAGIC", &magic, &len)) {
log_error(_msg_failed_length, type, name);
return 0;
if (force < DONT_PROMPT) {
log_error(MSG_FAILED_SIG_LENGTH, type, name);
return 0;
} else {
log_warn("WARNING: " MSG_FAILED_SIG_LENGTH MSG_WIPING_SKIPPED, type, name);
return 2;
}
}
} else if (!blkid_probe_lookup_value(probe, "PTTYPE", &type, NULL)) {
if (blkid_probe_lookup_value(probe, "PTMAGIC_OFFSET", &offset, NULL)) {
log_error(_msg_failed_offset, type, name);
return 0;
if (force < DONT_PROMPT) {
log_error(MSG_FAILED_SIG_OFFSET, type, name);
return 0;
} else {
log_warn("WARNING: " MSG_FAILED_SIG_OFFSET MSG_WIPING_SKIPPED, type, name);
return 2;
}
}
if (blkid_probe_lookup_value(probe, "PTMAGIC", &magic, &len)) {
log_error(_msg_failed_length, type, name);
return 0;
if (force < DONT_PROMPT) {
log_error(MSG_FAILED_SIG_LENGTH, type, name);
return 0;
} else {
log_warn("WARNING: " MSG_FAILED_SIG_LENGTH MSG_WIPING_SKIPPED, type, name);
return 2;
}
}
usage = "partition table";
} else

View File

@@ -24,10 +24,6 @@
#include <stdarg.h>
#define SIZE_BUF 128
typedef enum { SIZE_LONG = 0, SIZE_SHORT = 1, SIZE_UNIT = 2 } size_len_t;
static const struct {
alloc_policy_t alloc;
const char str[14]; /* must be changed when size extends 13 chars */
@@ -86,6 +82,38 @@ alloc_policy_t get_alloc_from_string(const char *str)
return ALLOC_INVALID;
}
const char *get_lock_type_string(lock_type_t lock_type)
{
switch (lock_type) {
case LOCK_TYPE_INVALID:
return "invalid";
case LOCK_TYPE_NONE:
return "none";
case LOCK_TYPE_CLVM:
return "clvm";
case LOCK_TYPE_DLM:
return "dlm";
case LOCK_TYPE_SANLOCK:
return "sanlock";
}
return "invalid";
}
lock_type_t get_lock_type_from_string(const char *str)
{
if (!str)
return LOCK_TYPE_NONE;
if (!strcmp(str, "none"))
return LOCK_TYPE_NONE;
if (!strcmp(str, "clvm"))
return LOCK_TYPE_CLVM;
if (!strcmp(str, "dlm"))
return LOCK_TYPE_DLM;
if (!strcmp(str, "sanlock"))
return LOCK_TYPE_SANLOCK;
return LOCK_TYPE_INVALID;
}
static const char *_percent_types[7] = { "NONE", "VG", "FREE", "LV", "PVS", "ORIGIN" };
const char *get_percent_string(percent_type_t def)
@@ -95,168 +123,49 @@ const char *get_percent_string(percent_type_t def)
const char *display_lvname(const struct logical_volume *lv)
{
/* On allocation failure, just return the LV name. */
return lv_fullname_dup(lv->vg->cmd->mem, lv) ? : lv->name;
}
char *name;
int r;
#define BASE_UNKNOWN 0
#define BASE_SHARED 1
#define BASE_1024 8
#define BASE_1000 15
#define BASE_SPECIAL 21
#define NUM_UNIT_PREFIXES 6
#define NUM_SPECIAL 3
if ((lv->vg->cmd->display_lvname_idx + NAME_LEN) >= sizeof((lv->vg->cmd->display_buffer)))
lv->vg->cmd->display_lvname_idx = 0;
name = lv->vg->cmd->display_buffer + lv->vg->cmd->display_lvname_idx;
r = dm_snprintf(name, NAME_LEN, "%s/%s", lv->vg->name, lv->name);
if (r < 0) {
log_error("Full LV name \"%s/%s\" is too long.", lv->vg->name, lv->name);
return NULL;
}
lv->vg->cmd->display_lvname_idx += r + 1;
return name;
}
/* Size supplied in sectors */
static const char *_display_size(const struct cmd_context *cmd,
uint64_t size, size_len_t sl)
uint64_t size, dm_size_suffix_t suffix_type)
{
unsigned base = BASE_UNKNOWN;
unsigned s;
int suffix, precision;
uint64_t byte = UINT64_C(0);
uint64_t units = UINT64_C(1024);
char *size_buf = NULL;
const char * const size_str[][3] = {
/* BASE_UNKNOWN */
{" ", " ", " "}, /* [0] */
/* BASE_SHARED - Used if cmd->si_unit_consistency = 0 */
{" Exabyte", " EB", "E"}, /* [1] */
{" Petabyte", " PB", "P"}, /* [2] */
{" Terabyte", " TB", "T"}, /* [3] */
{" Gigabyte", " GB", "G"}, /* [4] */
{" Megabyte", " MB", "M"}, /* [5] */
{" Kilobyte", " KB", "K"}, /* [6] */
{" Byte ", " B", "B"}, /* [7] */
/* BASE_1024 - Used if cmd->si_unit_consistency = 1 */
{" Exbibyte", " EiB", "e"}, /* [8] */
{" Pebibyte", " PiB", "p"}, /* [9] */
{" Tebibyte", " TiB", "t"}, /* [10] */
{" Gibibyte", " GiB", "g"}, /* [11] */
{" Mebibyte", " MiB", "m"}, /* [12] */
{" Kibibyte", " KiB", "k"}, /* [13] */
{" Byte ", " B", "b"}, /* [14] */
/* BASE_1000 - Used if cmd->si_unit_consistency = 1 */
{" Exabyte", " EB", "E"}, /* [15] */
{" Petabyte", " PB", "P"}, /* [16] */
{" Terabyte", " TB", "T"}, /* [17] */
{" Gigabyte", " GB", "G"}, /* [18] */
{" Megabyte", " MB", "M"}, /* [19] */
{" Kilobyte", " kB", "K"}, /* [20] */
/* BASE_SPECIAL */
{" Byte ", " B ", "B"}, /* [21] (shared with BASE_1000) */
{" Units ", " Un", "U"}, /* [22] */
{" Sectors ", " Se", "S"}, /* [23] */
};
if (!(size_buf = dm_pool_alloc(cmd->mem, SIZE_BUF))) {
log_error("no memory for size display buffer");
return "";
}
suffix = cmd->current_settings.suffix;
if (!cmd->si_unit_consistency) {
/* Case-independent match */
for (s = 0; s < NUM_UNIT_PREFIXES; s++)
if (toupper((int) cmd->current_settings.unit_type) ==
*size_str[BASE_SHARED + s][2]) {
base = BASE_SHARED;
break;
}
} else {
/* Case-dependent match for powers of 1000 */
for (s = 0; s < NUM_UNIT_PREFIXES; s++)
if (cmd->current_settings.unit_type ==
*size_str[BASE_1000 + s][2]) {
base = BASE_1000;
break;
}
/* Case-dependent match for powers of 1024 */
if (base == BASE_UNKNOWN)
for (s = 0; s < NUM_UNIT_PREFIXES; s++)
if (cmd->current_settings.unit_type ==
*size_str[BASE_1024 + s][2]) {
base = BASE_1024;
break;
}
}
if (base == BASE_UNKNOWN)
/* Check for special units - s, b or u */
for (s = 0; s < NUM_SPECIAL; s++)
if (toupper((int) cmd->current_settings.unit_type) ==
*size_str[BASE_SPECIAL + s][2]) {
base = BASE_SPECIAL;
break;
}
if (size == UINT64_C(0)) {
if (base == BASE_UNKNOWN)
s = 0;
sprintf(size_buf, "0%s", suffix ? size_str[base + s][sl] : "");
return size_buf;
}
size *= UINT64_C(512);
if (base != BASE_UNKNOWN)
byte = cmd->current_settings.unit_factor;
else {
/* Human-readable style */
if (cmd->current_settings.unit_type == 'H') {
units = UINT64_C(1000);
base = BASE_1000;
} else {
units = UINT64_C(1024);
base = BASE_1024;
}
if (!cmd->si_unit_consistency)
base = BASE_SHARED;
byte = units * units * units * units * units * units;
for (s = 0; s < NUM_UNIT_PREFIXES && size < byte; s++)
byte /= units;
suffix = 1;
}
/* FIXME Make precision configurable */
switch (toupper(*size_str[base + s][SIZE_UNIT])) {
case 'B':
case 'S':
precision = 0;
break;
default:
precision = 2;
}
snprintf(size_buf, SIZE_BUF - 1, "%.*f%s", precision,
(double) size / byte, suffix ? size_str[base + s][sl] : "");
return size_buf;
return dm_size_to_string(cmd->mem, size, cmd->current_settings.unit_type,
cmd->si_unit_consistency,
cmd->current_settings.unit_factor,
cmd->current_settings.suffix,
suffix_type);
}
const char *display_size_long(const struct cmd_context *cmd, uint64_t size)
{
return _display_size(cmd, size, SIZE_LONG);
return _display_size(cmd, size, DM_SIZE_LONG);
}
const char *display_size_units(const struct cmd_context *cmd, uint64_t size)
{
return _display_size(cmd, size, SIZE_UNIT);
return _display_size(cmd, size, DM_SIZE_UNIT);
}
const char *display_size(const struct cmd_context *cmd, uint64_t size)
{
return _display_size(cmd, size, SIZE_SHORT);
return _display_size(cmd, size, DM_SIZE_SHORT);
}
void pvdisplay_colons(const struct physical_volume *pv)
@@ -474,7 +383,7 @@ int lvdisplay_full(struct cmd_context *cmd,
log_print("LV UUID %s", uuid);
log_print("LV Write Access %s", access_str);
log_print("LV Creation host, time %s, %s",
lv_host_dup(cmd->mem, lv), lv_time_dup(cmd->mem, lv));
lv_host_dup(cmd->mem, lv), lv_time_dup(cmd->mem, lv, 1));
if (lv_is_origin(lv)) {
log_print("LV snapshot status source of");

View File

@@ -64,6 +64,9 @@ const char *get_alloc_string(alloc_policy_t alloc);
char alloc_policy_char(alloc_policy_t alloc);
alloc_policy_t get_alloc_from_string(const char *str);
const char *get_lock_type_string(lock_type_t lock_type);
lock_type_t get_lock_type_from_string(const char *str);
const char *get_percent_string(percent_type_t def);
char yes_no_prompt(const char *prompt, ...) __attribute__ ((format(printf, 1, 2)));

View File

@@ -164,7 +164,7 @@ int export_pv(struct cmd_context *cmd, struct dm_pool *mem __attribute__((unused
/* Is VG already exported or being exported? */
if (vg && vg_is_exported(vg)) {
/* Does system_id need setting? */
if (!*vg->lvm1_system_id ||
if (!vg->lvm1_system_id || !*vg->lvm1_system_id ||
strncmp(vg->lvm1_system_id, EXPORTED_TAG,
sizeof(EXPORTED_TAG) - 1)) {
if (!generate_lvm1_system_id(cmd, (char *)pvd->system_id, EXPORTED_TAG))

View File

@@ -372,19 +372,61 @@ static int _print_flag_config(struct formatter *f, uint64_t status, int type)
return 1;
}
static int _out_tags(struct formatter *f, struct dm_list *tagsl)
static char *_alloc_printed_str_list(struct dm_list *list)
{
char *tag_buffer;
struct dm_str_list *sl;
int first = 1;
size_t size = 0;
char *buffer, *buf;
if (!dm_list_empty(tagsl)) {
if (!(tag_buffer = alloc_printed_tags(tagsl)))
dm_list_iterate_items(sl, list)
/* '"' + item + '"' + ',' + ' ' */
size += strlen(sl->str) + 4;
/* '[' + ']' + '\0' */
size += 3;
if (!(buffer = buf = dm_malloc(size))) {
log_error("Could not allocate memory for string list buffer.");
return NULL;
}
if (!emit_to_buffer(&buf, &size, "["))
goto_bad;
dm_list_iterate_items(sl, list) {
if (!first) {
if (!emit_to_buffer(&buf, &size, ", "))
goto_bad;
} else
first = 0;
if (!emit_to_buffer(&buf, &size, "\"%s\"", sl->str))
goto_bad;
}
if (!emit_to_buffer(&buf, &size, "]"))
goto_bad;
return buffer;
bad:
dm_free(buffer);
return_NULL;
}
static int _out_list(struct formatter *f, struct dm_list *list,
const char *list_name)
{
char *buffer;
if (!dm_list_empty(list)) {
if (!(buffer = _alloc_printed_str_list(list)))
return_0;
if (!out_text(f, "tags = %s", tag_buffer)) {
dm_free(tag_buffer);
if (!out_text(f, "%s = %s", list_name, buffer)) {
dm_free(buffer);
return_0;
}
dm_free(tag_buffer);
dm_free(buffer);
}
return 1;
@@ -422,7 +464,7 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
if (!_print_flag_config(f, status, VG_FLAGS))
return_0;
if (!_out_tags(f, &vg->tags))
if (!_out_list(f, &vg->tags, "tags"))
return_0;
if (vg->system_id && *vg->system_id)
@@ -430,8 +472,11 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
else if (vg->lvm1_system_id && *vg->lvm1_system_id)
outf(f, "system_id = \"%s\"", vg->lvm1_system_id);
if (vg->lock_type)
if (vg->lock_type) {
outf(f, "lock_type = \"%s\"", vg->lock_type);
if (vg->lock_args)
outf(f, "lock_args = \"%s\"", vg->lock_args);
}
outsize(f, (uint64_t) vg->extent_size, "extent_size = %u",
vg->extent_size);
@@ -509,7 +554,7 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
if (!_print_flag_config(f, pv->status, PV_FLAGS))
return_0;
if (!_out_tags(f, &pv->tags))
if (!_out_list(f, &pv->tags, "tags"))
return_0;
outsize(f, pv->size, "dev_size = %" PRIu64, pv->size);
@@ -545,7 +590,7 @@ static int _print_segment(struct formatter *f, struct volume_group *vg,
outnl(f);
outf(f, "type = \"%s\"", seg->segtype->name);
if (!_out_tags(f, &seg->tags))
if (!_out_list(f, &seg->tags, "tags"))
return_0;
if (seg->segtype->ops->text_export &&
@@ -641,7 +686,7 @@ static int _print_lv(struct formatter *f, struct logical_volume *lv)
if (!_print_flag_config(f, status, LV_FLAGS))
return_0;
if (!_out_tags(f, &lv->tags))
if (!_out_list(f, &lv->tags, "tags"))
return_0;
if (lv->timestamp) {
@@ -657,6 +702,9 @@ static int _print_lv(struct formatter *f, struct logical_volume *lv)
lv->timestamp);
}
if (lv->lock_args)
outf(f, "lock_args = \"%s\"", lv->lock_args);
if (lv->alloc != ALLOC_INHERIT)
outf(f, "allocation_policy = \"%s\"",
get_alloc_string(lv->alloc));

View File

@@ -67,6 +67,7 @@ static const struct flag _lv_flags[] = {
{LV_NOSCAN, NULL, 0},
{LV_TEMPORARY, NULL, 0},
{POOL_METADATA_SPARE, NULL, 0},
{LOCKD_SANLOCK_LV, NULL, 0},
{RAID, NULL, 0},
{RAID_META, NULL, 0},
{RAID_IMAGE, NULL, 0},

View File

@@ -2237,7 +2237,7 @@ static int _text_pv_add_metadata_area(const struct format_type *fmt,
if (limit_applied)
log_very_verbose("Using limited metadata area size on %s "
"with value %" PRIu64 " (limited by %s of "
"%" PRIu64 ").", pv_dev_name(pv),
FMTu64 ").", pv_dev_name(pv),
mda_size, limit_name, limit);
if (mda_size) {
@@ -2491,7 +2491,7 @@ struct format_type *create_text_format(struct cmd_context *cmd)
goto bad;
}
if ((cn = find_config_tree_node(cmd, metadata_dirs_CFG, NULL))) {
if ((cn = find_config_tree_array(cmd, metadata_dirs_CFG, NULL))) {
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != DM_CFG_STRING) {
log_error("Invalid string in config file: "

View File

@@ -47,7 +47,8 @@ struct text_vg_version_ops {
int (*check_version) (const struct dm_config_tree * cf);
struct volume_group *(*read_vg) (struct format_instance * fid,
const struct dm_config_tree *cf,
unsigned use_cached_pvs);
unsigned use_cached_pvs,
unsigned allow_lvmetad_extensions);
void (*read_desc) (struct dm_pool * mem, const struct dm_config_tree *cf,
time_t *when, char **desc);
int (*read_vgname) (const struct format_type *fmt,
@@ -60,9 +61,6 @@ struct text_vg_version_ops *text_vg_vsn1_init(void);
int print_flags(uint64_t status, int type, char *buffer, size_t size);
int read_flags(uint64_t *status, int type, const struct dm_config_value *cv);
char *alloc_printed_tags(struct dm_list *tags);
int read_tags(struct dm_pool *mem, struct dm_list *tags, const struct dm_config_value *cv);
int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp);
size_t text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf);
struct volume_group *text_vg_import_file(struct format_instance *fid,

View File

@@ -146,7 +146,7 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
if (!(*vsn)->check_version(cft))
continue;
if (!(vg = (*vsn)->read_vg(fid, cft, single_device)))
if (!(vg = (*vsn)->read_vg(fid, cft, single_device, 0)))
goto_out;
(*vsn)->read_desc(vg->vgmem, cft, when, desc);
@@ -174,8 +174,9 @@ struct volume_group *text_vg_import_file(struct format_instance *fid,
when, desc);
}
struct volume_group *import_vg_from_config_tree(const struct dm_config_tree *cft,
struct format_instance *fid)
static struct volume_group *_import_vg_from_config_tree(const struct dm_config_tree *cft,
struct format_instance *fid,
unsigned allow_lvmetad_extensions)
{
struct volume_group *vg = NULL;
struct text_vg_version_ops **vsn;
@@ -190,7 +191,7 @@ struct volume_group *import_vg_from_config_tree(const struct dm_config_tree *cft
* The only path to this point uses cached vgmetadata,
* so it can use cached PV state too.
*/
if (!(vg = (*vsn)->read_vg(fid, cft, 1)))
if (!(vg = (*vsn)->read_vg(fid, cft, 1, allow_lvmetad_extensions)))
stack;
else if ((vg_missing = vg_missing_pv_count(vg))) {
log_verbose("There are %d physical volumes missing.",
@@ -203,3 +204,15 @@ struct volume_group *import_vg_from_config_tree(const struct dm_config_tree *cft
return vg;
}
struct volume_group *import_vg_from_config_tree(const struct dm_config_tree *cft,
struct format_instance *fid)
{
return _import_vg_from_config_tree(cft, fid, 0);
}
struct volume_group *import_vg_from_lvmetad_config_tree(const struct dm_config_tree *cft,
struct format_instance *fid)
{
return _import_vg_from_config_tree(cft, fid, 1);
}

View File

@@ -20,11 +20,13 @@
#include "toolcontext.h"
#include "lvmcache.h"
#include "lvmetad.h"
#include "lvmlockd.h"
#include "lv_alloc.h"
#include "pv_alloc.h"
#include "segtype.h"
#include "text_import.h"
#include "defaults.h"
#include "str_list.h"
typedef int (*section_fn) (struct format_instance * fid,
struct volume_group * vg, const struct dm_config_node * pvn,
@@ -153,6 +155,26 @@ static int _read_flag_config(const struct dm_config_node *n, uint64_t *status, i
return 1;
}
static int _read_str_list(struct dm_pool *mem, struct dm_list *list, const struct dm_config_value *cv)
{
if (cv->type == DM_CFG_EMPTY_ARRAY)
return 1;
while (cv) {
if (cv->type != DM_CFG_STRING) {
log_error("Found an item that is not a string");
return 0;
}
if (!str_list_add(mem, list, dm_pool_strdup(mem, cv->v.str)))
return_0;
cv = cv->next;
}
return 1;
}
static int _read_pv(struct format_instance *fid,
struct volume_group *vg, const struct dm_config_node *pvn,
const struct dm_config_node *vgn __attribute__((unused)),
@@ -167,6 +189,8 @@ static int _read_pv(struct format_instance *fid,
const struct dm_config_value *cv;
uint64_t size, ba_start;
int outdated = !strcmp(pvn->parent->key, "outdated_pvs");
if (!(pvl = dm_pool_zalloc(mem, sizeof(*pvl))) ||
!(pvl->pv = dm_pool_zalloc(mem, sizeof(*pvl->pv))))
return_0;
@@ -212,7 +236,7 @@ static int _read_pv(struct format_instance *fid,
memcpy(&pv->vgid, &vg->id, sizeof(vg->id));
if (!_read_flag_config(pvn, &pv->status, PV_FLAGS)) {
if (!outdated && !_read_flag_config(pvn, &pv->status, PV_FLAGS)) {
log_error("Couldn't read status flags for physical volume.");
return 0;
}
@@ -234,13 +258,13 @@ static int _read_pv(struct format_instance *fid,
return 0;
}
if (!_read_uint64(pvn, "pe_start", &pv->pe_start)) {
if (!outdated && !_read_uint64(pvn, "pe_start", &pv->pe_start)) {
log_error("Couldn't read extent start value (pe_start) "
"for physical volume.");
return 0;
}
if (!_read_int32(pvn, "pe_count", &pv->pe_count)) {
if (!outdated && !_read_int32(pvn, "pe_count", &pv->pe_count)) {
log_error("Couldn't find extent count (pe_count) for "
"physical volume.");
return 0;
@@ -267,7 +291,7 @@ static int _read_pv(struct format_instance *fid,
/* Optional tags */
if (dm_config_get_list(pvn, "tags", &cv) &&
!(read_tags(mem, &pv->tags, cv))) {
!(_read_str_list(mem, &pv->tags, cv))) {
log_error("Couldn't read tags for physical volume %s in %s.",
pv_dev_name(pv), vg->name);
return 0;
@@ -299,7 +323,10 @@ static int _read_pv(struct format_instance *fid,
vg->extent_count += pv->pe_count;
vg->free_count += pv->pe_count;
add_pvl_to_vgs(vg, pvl);
if (outdated)
dm_list_add(&vg->pvs_outdated, &pvl->list);
else
add_pvl_to_vgs(vg, pvl);
return 1;
}
@@ -375,7 +402,7 @@ static int _read_segment(struct logical_volume *lv, const struct dm_config_node
/* Optional tags */
if (dm_config_get_list(sn_child, "tags", &cv) &&
!(read_tags(mem, &seg->tags, cv))) {
!(_read_str_list(mem, &seg->tags, cv))) {
log_error("Couldn't read tags for a segment of %s/%s.",
lv->vg->name, lv->name);
return 0;
@@ -573,6 +600,30 @@ static int _read_lvnames(struct format_instance *fid __attribute__((unused)),
return 0;
}
/*
* The LV lock_args string is generated in lvmlockd, and the content
* depends on the lock_type.
*
* lock_type dlm does not use LV lock_args, so the LV lock_args field
* is just set to "dlm".
*
* lock_type sanlock uses the LV lock_args field to save the
* location on disk of that LV's sanlock lock. The disk name is
* specified in the VG lock_args. The lock_args string begins
* with a version number, e.g. 1.0.0, followed by a colon, followed
* by a number. The number is the offset on disk where sanlock is
* told to find the LV's lock.
* e.g. lock_args = 1.0.0:70254592
* means that the lock is located at offset 70254592.
*
* The lvmlockd code for each specific lock manager also validates
* the lock_args before using it to access the lock manager.
*/
if (dm_config_get_str(lvn, "lock_args", &str)) {
if (!(lv->lock_args = dm_pool_strdup(mem, str)))
return_0;
}
lv->alloc = ALLOC_INHERIT;
if (dm_config_get_str(lvn, "allocation_policy", &str)) {
lv->alloc = get_alloc_from_string(str);
@@ -611,7 +662,7 @@ static int _read_lvnames(struct format_instance *fid __attribute__((unused)),
/* Optional tags */
if (dm_config_get_list(lvn, "tags", &cv) &&
!(read_tags(mem, &lv->tags, cv))) {
!(_read_str_list(mem, &lv->tags, cv))) {
log_error("Couldn't read tags for logical volume %s/%s.",
vg->name, lv->name);
return 0;
@@ -638,6 +689,12 @@ static int _read_lvnames(struct format_instance *fid __attribute__((unused)),
vg->pool_metadata_spare_lv = lv;
}
if (!lv_is_visible(lv) && !strcmp(lv->name, LOCKD_SANLOCK_LV_NAME)) {
log_debug_metadata("Logical volume %s is sanlock lv.", lv->name);
lv->status |= LOCKD_SANLOCK_LV;
vg->sanlock_lv = lv;
}
return 1;
}
@@ -735,7 +792,8 @@ static int _read_sections(struct format_instance *fid,
static struct volume_group *_read_vg(struct format_instance *fid,
const struct dm_config_tree *cft,
unsigned use_cached_pvs)
unsigned use_cached_pvs,
unsigned allow_lvmetad_extensions)
{
const struct dm_config_node *vgn;
const struct dm_config_value *cv;
@@ -789,6 +847,32 @@ static struct volume_group *_read_vg(struct format_instance *fid,
goto bad;
}
/*
* The VG lock_args string is generated in lvmlockd, and the content
* depends on the lock_type. lvmlockd begins the lock_args string
* with a version number, e.g. 1.0.0, followed by a colon, followed
* by a string that depends on the lock manager. The string after
* the colon is information needed to use the lock manager for the VG.
*
* For sanlock, the string is the name of the internal LV used to store
* sanlock locks. lvmlockd needs to know where the locks are located
* so it can pass that location to sanlock which needs to access the locks.
* e.g. lock_args = 1.0.0:lvmlock
* means that the locks are located on the the LV "lvmlock".
*
* For dlm, the string is the dlm cluster name. lvmlockd needs to use
* a dlm lockspace in this cluster to use the VG.
* e.g. lock_args = 1.0.0:foo
* means that the host needs to be a member of the cluster "foo".
*
* The lvmlockd code for each specific lock manager also validates
* the lock_args before using it to access the lock manager.
*/
if (dm_config_get_str(vgn, "lock_args", &str)) {
if (!(vg->lock_args = dm_pool_strdup(vg->vgmem, str)))
goto bad;
}
if (!_read_id(&vg->id, vgn, "id")) {
log_error("Couldn't read uuid for volume group %s.", vg->name);
goto bad;
@@ -877,9 +961,15 @@ static struct volume_group *_read_vg(struct format_instance *fid,
goto bad;
}
if (allow_lvmetad_extensions)
_read_sections(fid, "outdated_pvs", _read_pv, vg,
vgn, pv_hash, lv_hash, 1, &scan_done_once);
else if (dm_config_has_node(vgn, "outdated_pvs"))
log_error(INTERNAL_ERROR "Unexpected outdated_pvs section in metadata of VG %s.", vg->name);
/* Optional tags */
if (dm_config_get_list(vgn, "tags", &cv) &&
!(read_tags(vg->vgmem, &vg->tags, cv))) {
!(_read_str_list(vg->vgmem, &vg->tags, cv))) {
log_error("Couldn't read tags for volume group %s.", vg->name);
goto bad;
}
@@ -941,6 +1031,11 @@ static void _read_desc(struct dm_pool *mem,
*when = u;
}
/*
* It would be more accurate to call this _read_vgsummary().
* It is used to read vgsummary information about a VG
* before locking and reading the VG via vg_read().
*/
static int _read_vgname(const struct format_type *fmt, const struct dm_config_tree *cft,
struct lvmcache_vgsummary *vgsummary)
{
@@ -977,6 +1072,8 @@ static int _read_vgname(const struct format_type *fmt, const struct dm_config_tr
return 0;
}
dm_config_get_str(vgn, "lock_type", &vgsummary->lock_type);
return 1;
}

View File

@@ -1,82 +0,0 @@
/*
* Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2005 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 "import-export.h"
#include "str_list.h"
#include "lvm-string.h"
char *alloc_printed_tags(struct dm_list *tagsl)
{
struct dm_str_list *sl;
int first = 1;
size_t size = 0;
char *buffer, *buf;
dm_list_iterate_items(sl, tagsl)
/* '"' + tag + '"' + ',' + ' ' */
size += strlen(sl->str) + 4;
/* '[' + ']' + '\0' */
size += 3;
if (!(buffer = buf = dm_malloc(size))) {
log_error("Could not allocate memory for tag list buffer.");
return NULL;
}
if (!emit_to_buffer(&buf, &size, "["))
goto_bad;
dm_list_iterate_items(sl, tagsl) {
if (!first) {
if (!emit_to_buffer(&buf, &size, ", "))
goto_bad;
} else
first = 0;
if (!emit_to_buffer(&buf, &size, "\"%s\"", sl->str))
goto_bad;
}
if (!emit_to_buffer(&buf, &size, "]"))
goto_bad;
return buffer;
bad:
dm_free(buffer);
return_NULL;
}
int read_tags(struct dm_pool *mem, struct dm_list *tagsl, const struct dm_config_value *cv)
{
if (cv->type == DM_CFG_EMPTY_ARRAY)
return 1;
while (cv) {
if (cv->type != DM_CFG_STRING) {
log_error("Found a tag that is not a string");
return 0;
}
if (!str_list_add(mem, tagsl, dm_pool_strdup(mem, cv->v.str)))
return_0;
cv = cv->next;
}
return 1;
}

View File

@@ -119,8 +119,9 @@ int init_locking(int type, struct cmd_context *cmd, int suppress_messages)
switch (type) {
case 0:
init_no_locking(&_locking, cmd, suppress_messages);
log_warn("WARNING: Locking disabled. Be careful! "
"This could corrupt your metadata.");
log_warn_suppress(suppress_messages,
"WARNING: Locking disabled. Be careful! "
"This could corrupt your metadata.");
return 1;
case 1:

View File

@@ -195,9 +195,10 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
#define unlock_vg(cmd, vol) \
do { \
if (is_real_vg(vol)) \
sync_dev_names(cmd); \
(void) lock_vol(cmd, vol, LCK_VG_UNLOCK, NULL); \
if (is_real_vg(vol) && !sync_dev_names(cmd)) \
stack; \
if (!lock_vol(cmd, vol, LCK_VG_UNLOCK, NULL)) \
stack; \
} while (0)
#define unlock_and_release_vg(cmd, vg, vol) \
do { \

2578
lib/locking/lvmlockd.c Normal file

File diff suppressed because it is too large Load Diff

246
lib/locking/lvmlockd.h Normal file
View File

@@ -0,0 +1,246 @@
/*
* Copyright (C) 2014-2015 Red Hat, Inc.
*
* 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.
*/
#ifndef _LVMLOCKD_H
#define _LVMLOCKD_H
#include "config-util.h"
#include "daemon-client.h"
#define LOCKD_SANLOCK_LV_NAME "lvmlock"
/* lockd_gl flags */
#define LDGL_UPDATE_NAMES 0x00000001
/* lockd_lv flags */
#define LDLV_MODE_NO_SH 0x00000001
#define LDLV_PERSISTENT 0x00000002
/* lvmlockd result flags */
#define LD_RF_NO_LOCKSPACES 0x00000001
#define LD_RF_NO_GL_LS 0x00000002
#define LD_RF_WARN_GL_REMOVED 0x00000004
#define LD_RF_DUP_GL_LS 0x00000008
#define LD_RF_INACTIVE_LS 0x00000010
#define LD_RF_ADD_LS_ERROR 0x00000020
/* lockd_state flags */
#define LDST_EX 0x00000001
#define LDST_SH 0x00000002
#define LDST_FAIL_REQUEST 0x00000004
#define LDST_FAIL_NOLS 0x00000008
#define LDST_FAIL_STARTING 0x00000010
#define LDST_FAIL_OTHER 0x00000020
#define LDST_FAIL (LDST_FAIL_REQUEST | LDST_FAIL_NOLS | LDST_FAIL_STARTING | LDST_FAIL_OTHER)
#ifdef LVMLOCKD_SUPPORT
/* lvmlockd connection and communication */
void lvmlockd_set_socket(const char *sock);
void lvmlockd_set_use(int use);
int lvmlockd_use(void);
void lvmlockd_init(struct cmd_context *cmd);
void lvmlockd_connect(void);
void lvmlockd_disconnect(void);
/* vgcreate/vgremove use init/free */
int lockd_init_vg(struct cmd_context *cmd, struct volume_group *vg, const char *lock_type, int lv_lock_count);
int lockd_free_vg_before(struct cmd_context *cmd, struct volume_group *vg);
void lockd_free_vg_final(struct cmd_context *cmd, struct volume_group *vg);
/* vgrename */
int lockd_rename_vg_before(struct cmd_context *cmd, struct volume_group *vg);
int lockd_rename_vg_final(struct cmd_context *cmd, struct volume_group *vg, int success);
/* start and stop the lockspace for a vg */
int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg);
int lockd_stop_vg(struct cmd_context *cmd, struct volume_group *vg);
int lockd_start_wait(struct cmd_context *cmd);
/* locking */
int lockd_gl_create(struct cmd_context *cmd, const char *def_mode, const char *vg_lock_type);
int lockd_gl(struct cmd_context *cmd, const char *def_mode, uint32_t flags);
int lockd_vg(struct cmd_context *cmd, const char *vg_name, const char *def_mode,
uint32_t flags, uint32_t *lockd_state);
int lockd_vg_update(struct volume_group *vg);
int lockd_lv_name(struct cmd_context *cmd, struct volume_group *vg,
const char *lv_name, struct id *lv_id,
const char *lock_args, const char *def_mode, uint32_t flags);
int lockd_lv(struct cmd_context *cmd, struct logical_volume *lv,
const char *def_mode, uint32_t flags);
/* lvcreate/lvremove use init/free */
int lockd_init_lv(struct cmd_context *cmd, struct volume_group *vg, struct logical_volume *lv,
struct lvcreate_params *lp);
int lockd_init_lv_args(struct cmd_context *cmd, struct volume_group *vg,
struct logical_volume *lv, const char *lock_type, const char **lock_args);
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);
int handle_sanlock_lv(struct cmd_context *cmd, struct volume_group *vg);
int lockd_lv_uses_lock(struct logical_volume *lv);
#else /* LVMLOCKD_SUPPORT */
static inline void lvmlockd_set_socket(const char *sock)
{
}
static inline void lvmlockd_set_use(int use)
{
}
static inline void lvmlockd_init(struct cmd_context *cmd)
{
}
static inline void lvmlockd_disconnect(void)
{
}
static inline void lvmlockd_connect(void)
{
}
static inline int lvmlockd_use(void)
{
return 0;
}
static inline int lockd_init_vg(struct cmd_context *cmd, struct volume_group *vg, const char *lock_type, int lv_lock_count)
{
return 1;
}
static inline int lockd_free_vg_before(struct cmd_context *cmd, struct volume_group *vg)
{
return 1;
}
static inline void lockd_free_vg_final(struct cmd_context *cmd, struct volume_group *vg)
{
return;
}
static inline int lockd_rename_vg_before(struct cmd_context *cmd, struct volume_group *vg)
{
return 1;
}
static inline int lockd_rename_vg_final(struct cmd_context *cmd, struct volume_group *vg, int success)
{
return 1;
}
static inline int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg)
{
return 0;
}
static inline int lockd_stop_vg(struct cmd_context *cmd, struct volume_group *vg)
{
return 0;
}
static inline int lockd_start_wait(struct cmd_context *cmd)
{
return 0;
}
static inline int lockd_gl_create(struct cmd_context *cmd, const char *def_mode, const char *vg_lock_type)
{
/*
* When lvm is built without lvmlockd support, creating a VG with
* a shared lock type should fail.
*/
if (is_lockd_type(vg_lock_type)) {
log_error("Using a shared lock type requires lvmlockd.");
return 0;
}
return 1;
}
static inline int lockd_gl(struct cmd_context *cmd, const char *def_mode, uint32_t flags)
{
return 1;
}
static inline int lockd_vg(struct cmd_context *cmd, const char *vg_name, const char *def_mode,
uint32_t flags, uint32_t *lockd_state)
{
*lockd_state = 0;
return 1;
}
static inline int lockd_vg_update(struct volume_group *vg)
{
return 1;
}
static inline int lockd_lv_name(struct cmd_context *cmd, struct volume_group *vg,
const char *lv_name, struct id *lv_id,
const char *lock_args, const char *def_mode, uint32_t flags)
{
return 1;
}
static inline int lockd_lv(struct cmd_context *cmd, struct logical_volume *lv,
const char *def_mode, uint32_t flags)
{
return 1;
}
static inline int lockd_init_lv(struct cmd_context *cmd, struct volume_group *vg,
struct logical_volume *lv, struct lvcreate_params *lp)
{
return 1;
}
static inline int lockd_init_lv_args(struct cmd_context *cmd, struct volume_group *vg,
struct logical_volume *lv, const char *lock_type, const char **lock_args)
{
return 1;
}
static inline int lockd_free_lv(struct cmd_context *cmd, struct volume_group *vg,
const char *lv_name, struct id *lv_id, const char *lock_args)
{
return 1;
}
static inline const char *lockd_running_lock_type(struct cmd_context *cmd)
{
log_error("Using a shared lock type requires lvmlockd.");
return NULL;
}
static inline int handle_sanlock_lv(struct cmd_context *cmd, struct volume_group *vg)
{
return 0;
}
static inline int lockd_lv_uses_lock(struct logical_volume *lv)
{
return 0;
}
#endif /* LVMLOCKD_SUPPORT */
#endif /* _LVMLOCKD_H */

View File

@@ -36,7 +36,7 @@ static int _indent = 1;
static int _log_suppress = 0;
static char _msg_prefix[30] = " ";
static int _already_logging = 0;
static int _abort_on_internal_errors = 0;
static int _abort_on_internal_errors_config = 0;
static lvm2_log_fn_t _lvm2_log_fn = NULL;
@@ -69,7 +69,7 @@ void init_log_file(const char *log_file, int append)
static const char statfile[] = "/proc/self/stat";
const char *env;
int pid;
long long starttime;
unsigned long long starttime;
FILE *st;
int i = 0;
@@ -92,9 +92,6 @@ void init_log_file(const char *log_file, int append)
"%llu", &pid, &starttime) != 2) {
log_warn("WARNING: Cannot parse content of %s.", statfile);
} else {
if (fclose(st))
log_sys_debug("fclose", statfile);
if (dm_snprintf(_log_file_path, sizeof(_log_file_path),
"%s_%s_%d_%lld", log_file, env, pid, starttime) < 0) {
log_warn("WARNING: Debug log file path is too long for epoch.");
@@ -104,7 +101,11 @@ void init_log_file(const char *log_file, int append)
append = 1; /* force */
}
}
if (st && fclose(st))
log_sys_debug("fclose", statfile);
}
no_epoch:
if (!(_log_file = fopen(log_file, append ? "a" : "w"))) {
log_sys_error("fopen", log_file);
@@ -217,9 +218,10 @@ void init_indent(int indent)
_indent = indent;
}
/* If present, environment setting will override this. */
void init_abort_on_internal_errors(int fatal)
{
_abort_on_internal_errors = fatal;
_abort_on_internal_errors_config = fatal;
}
void reset_lvm_errno(int store_errmsg)
@@ -276,10 +278,24 @@ void print_log(int level, const char *file, int line, int dm_errno_or_class,
size_t msglen;
const char *indent_spaces = "";
FILE *stream;
static int _abort_on_internal_errors_env_present = -1;
static int _abort_on_internal_errors_env = 0;
char *env_str;
level &= ~(_LOG_STDERR|_LOG_ONCE);
if (_abort_on_internal_errors &&
if (_abort_on_internal_errors_env_present < 0) {
if ((env_str = getenv("DM_ABORT_ON_INTERNAL_ERRORS"))) {
_abort_on_internal_errors_env_present = 1;
/* Set when env DM_ABORT_ON_INTERNAL_ERRORS is not "0" */
_abort_on_internal_errors_env = strcmp(env_str, "0");
} else
_abort_on_internal_errors_env_present = 0;
}
/* Use value from environment if present, otherwise use value from config. */
if (((_abort_on_internal_errors_env_present && _abort_on_internal_errors_env) ||
(!_abort_on_internal_errors_env_present && _abort_on_internal_errors_config)) &&
!strncmp(format, INTERNAL_ERROR, sizeof(INTERNAL_ERROR) - 1)) {
fatal_internal_error = 1;
/* Internal errors triggering abort cannot be suppressed. */
@@ -385,6 +401,8 @@ void print_log(int level, const char *file, int line, int dm_errno_or_class,
default:
/* Typically only log_warn goes to stdout */
stream = (use_stderr || (level != _LOG_WARN)) ? stderr : stdout;
if (stream == stderr)
fflush(stdout);
fprintf(stream, "%s%s%s%s", buf, log_command_name(),
_msg_prefix, indent_spaces);
vfprintf(stream, trformat, ap);

View File

@@ -37,8 +37,6 @@
*
*/
#include <stdio.h> /* FILE */
#include <string.h> /* strerror() */
#include <errno.h>
#define EUNCLASSIFIED -1 /* Generic error code */

View File

@@ -106,6 +106,7 @@ static void _explain_error_codes(int retcode)
/* lvmpolld specific return codes */
case LVMPD_RET_DUP_FAILED:
log_error("lvmpolld failed to duplicate file descriptors.");
/* fall through */
case LVMPD_RET_EXC_FAILED:
log_error("lvmpolld failed to exec() lvm binary.");
break;
@@ -146,7 +147,7 @@ static struct progress_info _request_progress_info(const char *uuid, unsigned ab
}
if (abort_polling &&
!daemon_request_extend(req, LVMPD_PARM_ABORT " = %d", abort_polling, NULL)) {
!daemon_request_extend(req, LVMPD_PARM_ABORT " = %d", (int64_t)abort_polling, NULL)) {
log_error("Failed to create " LVMPD_REQ_PROGRESS " request.");
goto out_req;
}
@@ -227,14 +228,14 @@ static int _process_poll_init(const struct cmd_context *cmd, const char *poll_ty
}
if (parms->aborting &&
!(daemon_request_extend(req, LVMPD_PARM_ABORT " = %d", parms->aborting, NULL))) {
!(daemon_request_extend(req, LVMPD_PARM_ABORT " = %d", (int64_t)(parms->aborting), NULL))) {
log_error("Failed to create %s request." , poll_type);
goto out_req;
}
if (cmd->handles_missing_pvs &&
!(daemon_request_extend(req, LVMPD_PARM_HANDLE_MISSING_PVS " = %d",
cmd->handles_missing_pvs, NULL))) {
(int64_t)(cmd->handles_missing_pvs), NULL))) {
log_error("Failed to create %s request." , poll_type);
goto out_req;
}
@@ -330,6 +331,8 @@ int lvmpolld_request_info(const struct poll_operation_id *id, const struct daemo
return 0;
}
log_debug_lvmpolld("Asking lvmpolld for progress status of an operation on %s/%s.",
id->vg_name, id->lv_name);
info = _request_progress_info(id->uuid, parms->aborting);
*finished = info.finished;

View File

@@ -29,15 +29,6 @@ struct daemon_parms;
struct poll_functions {
const char *(*get_copy_name_from_lv) (const struct logical_volume *lv);
struct volume_group *(*get_copy_vg) (struct cmd_context *cmd,
const char *name,
const char *uuid,
uint32_t flags);
struct logical_volume *(*get_copy_lv) (struct cmd_context *cmd,
struct volume_group *vg,
const char *name,
const char *uuid,
uint64_t lv_type);
progress_t (*poll_progress)(struct cmd_context *cmd,
struct logical_volume *lv,
const char *name,
@@ -79,14 +70,6 @@ progress_t poll_mirror_progress(struct cmd_context *cmd,
struct logical_volume *lv, const char *name,
struct daemon_parms *parms);
struct volume_group *poll_get_copy_vg(struct cmd_context *cmd, const char *name,
const char *uuid, uint32_t flags);
struct logical_volume *poll_get_copy_lv(struct cmd_context *cmd,
struct volume_group *vg,
const char *name, const char *uuid,
uint64_t lv_type);
int wait_for_single_lv(struct cmd_context *cmd, struct poll_operation_id *id,
struct daemon_parms *parms);

View File

@@ -322,7 +322,7 @@ int lv_cache_remove(struct logical_volume *cache_lv)
dirty_blocks = status->cache->dirty_blocks;
dm_pool_destroy(status->mem);
if (dirty_blocks) {
log_print_unless_silent("%" PRIu64 " blocks must still be flushed.",
log_print_unless_silent(FMTu64 " blocks must still be flushed.",
dirty_blocks);
sleep(1);
}
@@ -395,13 +395,13 @@ int lv_is_cache_origin(const struct logical_volume *lv)
return seg && lv_is_cache(seg->lv) && !lv_is_pending_delete(seg->lv) && (seg_lv(seg, 0) == lv);
}
int lv_cache_setpolicy(struct logical_volume *lv, struct dm_config_tree *policy)
int lv_cache_set_policy(struct logical_volume *lv, const char *name,
const struct dm_config_tree *settings)
{
struct lv_segment *seg = first_seg(lv);
const char *name;
struct dm_config_node *cn;
struct dm_config_tree *old = NULL, *new = NULL, *tmp = NULL;
int r = 0;
struct lv_segment *seg = first_seg(lv);
if (lv_is_cache(lv))
seg = first_seg(seg->pool_lv);
@@ -411,20 +411,21 @@ int lv_cache_setpolicy(struct logical_volume *lv, struct dm_config_tree *policy)
goto_out;
if (!(new = dm_config_create()))
goto_out;
new->root = policy->root;
new->root = settings->root;
old->root = seg->policy_settings;
new->cascade = old;
if (!(tmp = policy = dm_config_flatten(new)))
if (!(tmp = dm_config_flatten(new)))
goto_out;
}
if ((cn = dm_config_find_node(policy->root, "policy_settings")) &&
if ((cn = dm_config_find_node((tmp) ? tmp->root : settings->root, "policy_settings")) &&
!(seg->policy_settings = dm_config_clone_node_with_mem(lv->vg->vgmem, cn, 0)))
goto_out;
if ((name = dm_config_find_str(policy->root, "policy", NULL)) &&
!(seg->policy_name = dm_pool_strdup(lv->vg->vgmem, name)))
goto_out;
if (name && !(seg->policy_name = dm_pool_strdup(lv->vg->vgmem, name))) {
log_error("Failed to duplicate policy name.");
goto out;
}
restart: /* remove any 'default" nodes */
cn = seg->policy_settings ? seg->policy_settings->child : NULL;
@@ -439,12 +440,13 @@ restart: /* remove any 'default" nodes */
r = 1;
out:
if (old)
dm_config_destroy(old);
if (new)
dm_config_destroy(new);
if (tmp)
dm_config_destroy(tmp);
if (new)
dm_config_destroy(new);
if (old)
dm_config_destroy(old);
return r;
}

View File

@@ -20,6 +20,7 @@
#include "toolcontext.h"
#include "segtype.h"
#include "str_list.h"
#include "lvmlockd.h"
#include <time.h>
#include <sys/utsname.h>
@@ -78,7 +79,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),
"%" PRIu32, extent + seg->area_len - 1) < 0) {
FMTu32, extent + seg->area_len - 1) < 0) {
log_error("Extent number dm_snprintf failed");
return NULL;
}
@@ -873,17 +874,16 @@ int lv_set_creation(struct logical_volume *lv,
return 1;
}
char *lv_time_dup(struct dm_pool *mem, const struct logical_volume *lv)
char *lv_time_dup(struct dm_pool *mem, const struct logical_volume *lv, int iso_mode)
{
char buffer[50];
char buffer[4096];
struct tm *local_tm;
time_t ts = (time_t)lv->timestamp;
const char *format = iso_mode ? DEFAULT_TIME_FORMAT : lv->vg->cmd->time_format;
if (!ts ||
!(local_tm = localtime(&ts)) ||
/* FIXME: make this lvm.conf configurable */
!strftime(buffer, sizeof(buffer),
"%Y-%m-%d %T %z", local_tm))
!strftime(buffer, sizeof(buffer), format, local_tm))
buffer[0] = 0;
return dm_pool_strdup(mem, buffer);
@@ -911,6 +911,19 @@ static int _lv_is_exclusive(struct logical_volume *lv)
int lv_active_change(struct cmd_context *cmd, struct logical_volume *lv,
enum activation_change activate, int needs_exclusive)
{
const char *ay_with_mode = NULL;
if (activate == CHANGE_ASY)
ay_with_mode = "sh";
if (activate == CHANGE_AEY)
ay_with_mode = "ex";
if (is_change_activating(activate) &&
!lockd_lv(cmd, lv, ay_with_mode, LDLV_PERSISTENT)) {
log_error("Failed to lock logical volume %s/%s", lv->vg->name, lv->name);
return 0;
}
switch (activate) {
case CHANGE_AN:
deactivate:
@@ -953,7 +966,9 @@ exclusive:
if (!activate_lv_excl(cmd, lv))
return_0;
break;
default: /* CHANGE_AY */
case CHANGE_ASY:
case CHANGE_AY:
default:
if (needs_exclusive || _lv_is_exclusive(lv))
goto exclusive;
log_verbose("Activating logical volume \"%s\".", lv->name);
@@ -961,6 +976,10 @@ exclusive:
return_0;
}
if (!is_change_activating(activate) &&
!lockd_lv(cmd, lv, "un", LDLV_PERSISTENT))
log_error("Failed to unlock logical volume %s/%s", lv->vg->name, lv->name);
return 1;
}
@@ -1000,6 +1019,12 @@ char *lv_profile_dup(struct dm_pool *mem, const struct logical_volume *lv)
return dm_pool_strdup(mem, profile_name);
}
char *lv_lock_args_dup(struct dm_pool *mem, const struct logical_volume *lv)
{
const char *lock_args = lv->lock_args ? lv->lock_args : "";
return dm_pool_strdup(mem, lock_args);
}
/* For given LV find recursively the LV which holds lock for it */
const struct logical_volume *lv_lock_holder(const struct logical_volume *lv)
{

View File

@@ -51,7 +51,9 @@ struct logical_volume {
struct dm_list segs_using_this_lv;
uint64_t timestamp;
unsigned new_lock_args:1;
const char *hostname;
const char *lock_args;
};
struct lv_with_info_and_seg_status;
@@ -91,7 +93,7 @@ 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_seg_pe_ranges(struct dm_pool *mem, const struct lv_segment *seg);
char *lv_time_dup(struct dm_pool *mem, const struct logical_volume *lv);
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,
const char *hostname, uint64_t timestamp);
@@ -103,6 +105,7 @@ const struct logical_volume *lv_lock_holder(const struct logical_volume *lv);
const struct logical_volume *lv_ondisk(const struct logical_volume *lv);
struct profile *lv_config_profile(const struct logical_volume *lv);
char *lv_profile_dup(struct dm_pool *mem, const struct logical_volume *lv);
char *lv_lock_args_dup(struct dm_pool *mem, const struct logical_volume *lv);
int lv_mirror_image_in_sync(const struct logical_volume *lv);
int lv_raid_image_in_sync(const struct logical_volume *lv);
int lv_raid_healthy(const struct logical_volume *lv);

View File

@@ -30,6 +30,7 @@
#include "lvm-exec.h"
#include "lvm-signal.h"
#include "memlock.h"
#include "lvmlockd.h"
typedef enum {
PREFERRED,
@@ -73,6 +74,7 @@ struct alloc_state {
uint32_t areas_size;
uint32_t log_area_count_still_needed; /* Number of areas still needing to be allocated for the log */
uint32_t allocated; /* Total number of extents allocated so far */
uint32_t num_positional_areas; /* Number of parallel allocations that must be contiguous/cling */
};
struct lv_names {
@@ -1395,6 +1397,28 @@ int replace_lv_with_error_segment(struct logical_volume *lv)
return 1;
}
int lv_refresh_suspend_resume(struct cmd_context *cmd, struct logical_volume *lv)
{
if (!cmd->partial_activation && (lv->status & PARTIAL_LV)) {
log_error("Refusing refresh of partial LV %s."
" Use '--activationmode partial' to override.",
display_lvname(lv));
return 0;
}
if (!suspend_lv(cmd, lv)) {
log_error("Failed to suspend %s.", display_lvname(lv));
return 0;
}
if (!resume_lv(cmd, lv)) {
log_error("Failed to reactivate %s.", display_lvname(lv));
return 0;
}
return 1;
}
/*
* Remove given number of extents from LV.
*/
@@ -2219,6 +2243,10 @@ static int _is_condition(struct cmd_context *cmd __attribute__((unused)),
if (!pvmatch->condition(pvmatch, pvseg, pvmatch->pva))
return 1; /* Continue */
if (positional && (s >= pvmatch->alloc_state->num_positional_areas))
return 1;
/* FIXME The previous test should make this one redundant. */
if (positional && (s >= pvmatch->alloc_state->areas_size))
return 1;
@@ -2456,6 +2484,8 @@ static void _clear_areas(struct alloc_state *alloc_state)
{
uint32_t s;
alloc_state->num_positional_areas = 0;
for (s = 0; s < alloc_state->areas_size; s++)
alloc_state->areas[s].pva = NULL;
}
@@ -2498,9 +2528,10 @@ static void _report_needed_allocation_space(struct alloc_handle *ah,
metadata_count = alloc_state->log_area_count_still_needed;
}
log_debug_alloc("Still need %s%" PRIu32 " total extents from %" PRIu32 " remaining:",
log_debug_alloc("Still need %s%" PRIu32 " total extents from %" PRIu32 " remaining (%" PRIu32 " positional slots):",
ah->approx_alloc ? "up to " : "",
parallel_area_size * parallel_areas_count + metadata_size * metadata_count, pv_maps_size(pvms));
parallel_area_size * parallel_areas_count + metadata_size * metadata_count, pv_maps_size(pvms),
alloc_state->num_positional_areas);
log_debug_alloc(" %" PRIu32 " (%" PRIu32 " data/%" PRIu32
" parity) parallel areas of %" PRIu32 " extents each",
parallel_areas_count, ah->area_count, ah->parity_count, parallel_area_size);
@@ -2555,7 +2586,6 @@ static int _find_some_parallel_space(struct alloc_handle *ah,
struct pv_area *pva;
unsigned preferred_count = 0;
unsigned already_found_one;
unsigned ix_offset = 0; /* Offset for non-preferred allocations */
unsigned ix_log_offset; /* Offset to start of areas to use for log */
unsigned too_small_for_log_count; /* How many too small for log? */
unsigned iteration_count = 0; /* cling_to_alloced may need 2 iterations */
@@ -2565,27 +2595,28 @@ static int _find_some_parallel_space(struct alloc_handle *ah,
uint32_t devices_needed = ah->area_count + ah->parity_count;
uint32_t required;
/* ix_offset holds the number of parallel allocations that must be contiguous/cling */
_clear_areas(alloc_state);
_reset_unreserved(pvms);
/* num_positional_areas holds the number of parallel allocations that must be contiguous/cling */
/* These appear first in the array, so it is also the offset to the non-preferred allocations */
/* At most one of A_CONTIGUOUS_TO_LVSEG, A_CLING_TO_LVSEG or A_CLING_TO_ALLOCED may be set */
if (!(alloc_parms->flags & A_POSITIONAL_FILL))
ix_offset = 0;
alloc_state->num_positional_areas = 0;
else if (alloc_parms->flags & (A_CONTIGUOUS_TO_LVSEG | A_CLING_TO_LVSEG))
ix_offset = _stripes_per_mimage(alloc_parms->prev_lvseg) * alloc_parms->prev_lvseg->area_count;
alloc_state->num_positional_areas = _stripes_per_mimage(alloc_parms->prev_lvseg) * alloc_parms->prev_lvseg->area_count;
else if (alloc_parms->flags & A_CLING_TO_ALLOCED)
ix_offset = ah->area_count;
alloc_state->num_positional_areas = ah->area_count;
if (alloc_parms->alloc == ALLOC_NORMAL || (alloc_parms->flags & A_CLING_TO_ALLOCED))
log_debug_alloc("Cling_to_allocated is %sset",
alloc_parms->flags & A_CLING_TO_ALLOCED ? "" : "not ");
if (alloc_parms->flags & A_POSITIONAL_FILL)
log_debug_alloc("%u preferred area(s) to be filled positionally.", ix_offset);
log_debug_alloc("%u preferred area(s) to be filled positionally.", alloc_state->num_positional_areas);
else
log_debug_alloc("Areas to be sorted and filled sequentially.");
_clear_areas(alloc_state);
_reset_unreserved(pvms);
_report_needed_allocation_space(ah, alloc_state, pvms);
/* ix holds the number of areas found on other PVs */
@@ -2593,7 +2624,7 @@ static int _find_some_parallel_space(struct alloc_handle *ah,
if (log_iteration_count) {
log_debug_alloc("Found %u areas for %" PRIu32 " parallel areas and %" PRIu32 " log areas so far.", ix, devices_needed, alloc_state->log_area_count_still_needed);
} else if (iteration_count)
log_debug_alloc("Filled %u out of %u preferred areas so far.", preferred_count, ix_offset);
log_debug_alloc("Filled %u out of %u preferred areas so far.", preferred_count, alloc_state->num_positional_areas);
/*
* Provide for escape from the loop if no progress is made.
@@ -2634,7 +2665,7 @@ static int _find_some_parallel_space(struct alloc_handle *ah,
* not enough for the logs.
*/
if (log_iteration_count) {
for (s = devices_needed; s < ix + ix_offset; s++)
for (s = devices_needed; s < ix + alloc_state->num_positional_areas; s++)
if (alloc_state->areas[s].pva && alloc_state->areas[s].pva->map->pv == pvm->pv)
goto next_pv;
/* On a second pass, avoid PVs already used in an uncommitted area */
@@ -2682,8 +2713,8 @@ static int _find_some_parallel_space(struct alloc_handle *ah,
}
/* Reserve required amount of pva */
required = _calc_required_extents(ah, pva, ix + ix_offset - 1, max_to_allocate, alloc_parms->alloc);
if (!_reserve_required_area(ah, alloc_state, pva, required, ix + ix_offset - 1, pva->unreserved))
required = _calc_required_extents(ah, pva, ix + alloc_state->num_positional_areas - 1, max_to_allocate, alloc_parms->alloc);
if (!_reserve_required_area(ah, alloc_state, pva, required, ix + alloc_state->num_positional_areas - 1, pva->unreserved))
return_0;
}
@@ -2694,23 +2725,23 @@ static int _find_some_parallel_space(struct alloc_handle *ah,
/* With cling and contiguous we stop if we found a match for *all* the areas */
/* FIXME Rename these variables! */
if ((alloc_parms->alloc == ALLOC_ANYWHERE &&
ix + ix_offset >= devices_needed + alloc_state->log_area_count_still_needed) ||
(preferred_count == ix_offset &&
(ix_offset == devices_needed + alloc_state->log_area_count_still_needed)))
ix + alloc_state->num_positional_areas >= devices_needed + alloc_state->log_area_count_still_needed) ||
(preferred_count == alloc_state->num_positional_areas &&
(alloc_state->num_positional_areas == devices_needed + alloc_state->log_area_count_still_needed)))
break;
}
} while ((alloc_parms->alloc == ALLOC_ANYWHERE && last_ix != ix && ix < devices_needed + alloc_state->log_area_count_still_needed) ||
/* With cling_to_alloced and normal, if there were gaps in the preferred areas, have a second iteration */
(alloc_parms->alloc == ALLOC_NORMAL && preferred_count &&
(preferred_count < ix_offset || alloc_state->log_area_count_still_needed) &&
(preferred_count < alloc_state->num_positional_areas || alloc_state->log_area_count_still_needed) &&
(alloc_parms->flags & A_CLING_TO_ALLOCED) && !iteration_count++) ||
/* Extra iteration needed to fill log areas on PVs already used? */
(alloc_parms->alloc == ALLOC_NORMAL && preferred_count == ix_offset && !ah->mirror_logs_separate &&
(alloc_parms->alloc == ALLOC_NORMAL && preferred_count == alloc_state->num_positional_areas && !ah->mirror_logs_separate &&
(ix + preferred_count >= devices_needed) &&
(ix + preferred_count < devices_needed + alloc_state->log_area_count_still_needed) && !log_iteration_count++));
/* Non-zero ix means at least one USE_AREA was returned */
if (preferred_count < ix_offset && !(alloc_parms->flags & A_CLING_TO_ALLOCED) && !ix)
if (preferred_count < alloc_state->num_positional_areas && !(alloc_parms->flags & A_CLING_TO_ALLOCED) && !ix)
return 1;
if (ix + preferred_count < devices_needed + alloc_state->log_area_count_still_needed)
@@ -2725,17 +2756,17 @@ static int _find_some_parallel_space(struct alloc_handle *ah,
}
} else if (ix > 1) {
log_debug_alloc("Sorting %u areas", ix);
qsort(alloc_state->areas + ix_offset, ix, sizeof(*alloc_state->areas),
qsort(alloc_state->areas + alloc_state->num_positional_areas, ix, sizeof(*alloc_state->areas),
_comp_area);
}
/* If there are gaps in our preferred areas, fill them from the sorted part of the array */
if (preferred_count && preferred_count != ix_offset) {
if (preferred_count && preferred_count != alloc_state->num_positional_areas) {
for (s = 0; s < devices_needed; s++)
if (!alloc_state->areas[s].pva) {
alloc_state->areas[s].pva = alloc_state->areas[ix_offset].pva;
alloc_state->areas[s].used = alloc_state->areas[ix_offset].used;
alloc_state->areas[ix_offset++].pva = NULL;
alloc_state->areas[s].pva = alloc_state->areas[alloc_state->num_positional_areas].pva;
alloc_state->areas[s].used = alloc_state->areas[alloc_state->num_positional_areas].used;
alloc_state->areas[alloc_state->num_positional_areas++].pva = NULL;
}
}
@@ -2749,14 +2780,14 @@ static int _find_some_parallel_space(struct alloc_handle *ah,
/* FIXME This logic is due to its heritage and can be simplified! */
if (alloc_state->log_area_count_still_needed) {
/* How many areas are too small for the log? */
while (too_small_for_log_count < ix_offset + ix &&
(*(alloc_state->areas + ix_offset + ix - 1 -
while (too_small_for_log_count < alloc_state->num_positional_areas + ix &&
(*(alloc_state->areas + alloc_state->num_positional_areas + ix - 1 -
too_small_for_log_count)).used < ah->log_len)
too_small_for_log_count++;
ix_log_offset = ix_offset + ix - too_small_for_log_count - ah->log_area_count;
ix_log_offset = alloc_state->num_positional_areas + ix - too_small_for_log_count - ah->log_area_count;
}
if (ix + ix_offset < devices_needed +
if (ix + alloc_state->num_positional_areas < devices_needed +
(alloc_state->log_area_count_still_needed ? alloc_state->log_area_count_still_needed +
too_small_for_log_count : 0))
return 1;
@@ -2770,12 +2801,12 @@ static int _find_some_parallel_space(struct alloc_handle *ah,
/*
* This code covers the initial allocation - after that there is something to 'cling' to
* and we shouldn't get this far.
* ix_offset is assumed to be 0 with A_PARTITION_BY_TAGS.
* alloc_state->num_positional_areas is assumed to be 0 with A_PARTITION_BY_TAGS.
*
* FIXME Consider a second attempt with A_PARTITION_BY_TAGS if, for example, the largest area
* had all the tags set, but other areas don't.
*/
if ((alloc_parms->flags & A_PARTITION_BY_TAGS) && !ix_offset) {
if ((alloc_parms->flags & A_PARTITION_BY_TAGS) && !alloc_state->num_positional_areas) {
if (!_limit_to_one_area_per_tag(ah, alloc_state, ix_log_offset, &ix))
return_0;
@@ -3232,7 +3263,7 @@ static struct alloc_handle *_alloc_init(struct cmd_context *cmd,
ah->parallel_areas = parallel_areas;
if ((ah->cling_tag_list_cn = find_config_tree_node(cmd, allocation_cling_tag_list_CFG, NULL)))
if ((ah->cling_tag_list_cn = find_config_tree_array(cmd, allocation_cling_tag_list_CFG, NULL)))
(void) _validate_tag_list(ah->cling_tag_list_cn);
ah->maximise_cling = find_config_tree_bool(cmd, allocation_maximise_cling_CFG, NULL);
@@ -4333,7 +4364,7 @@ static int _fsadm_cmd(struct cmd_context *cmd,
argv[i++] = lv_path;
if (fcmd == FSADM_CMD_RESIZE) {
if (dm_snprintf(size_buf, sizeof(size_buf), "%" PRIu64 "K",
if (dm_snprintf(size_buf, sizeof(size_buf), FMTu64 "K",
(uint64_t) lp->extents * (vg->extent_size / 2)) < 0) {
log_error("Couldn't generate new LV size string");
return 0;
@@ -4566,7 +4597,9 @@ static int _lvresize_check_lv(struct cmd_context *cmd, struct logical_volume *lv
return 0;
}
if (!lv_is_visible(lv) && !lv_is_thin_pool_metadata(lv)) {
/* FIXME: use a status flag instead of the name "lvmlock". */
if (!lv_is_visible(lv) && !lv_is_thin_pool_metadata(lv) && strcmp(lv->name, "lvmlock")) {
log_error("Can't resize internal logical volume %s", lv->name);
return 0;
}
@@ -5062,16 +5095,6 @@ static int _lvresize_check_type(struct cmd_context *cmd, const struct logical_vo
if (lv_is_thin_volume(lv) && first_seg(lv)->external_lv &&
(lp->resize == LV_EXTEND)) {
/*
* TODO: currently we do not support extension of already reduced thin volume.
* But it might be possible to create combined mapping of some part of
* the external origin followed by zero target.
*/
if (first_seg(lv)->external_lv->size > lv->size) {
log_error("Extension of reduced thin volume with external origin is unsupported.");
return 0;
}
/* Validate thin target supports bigger size of thin volume then external origin */
if (first_seg(lv)->external_lv->size <= lv->size &&
!thin_pool_feature_supported(first_seg(lv)->pool_lv, THIN_FEATURE_EXTERNAL_ORIGIN_EXTEND)) {
@@ -5152,6 +5175,8 @@ static struct logical_volume *_lvresize_volume(struct cmd_context *cmd,
lp->extents - lv->le_count,
pvh, alloc, lp->approx_alloc))
return_NULL;
else if (!pool_check_overprovisioning(lv))
return_NULL;
if (old_extents == lv->le_count)
log_print_unless_silent("Size of logical volume %s unchanged from %s (%" PRIu32 " extents).",
@@ -5226,6 +5251,13 @@ int lv_resize(struct cmd_context *cmd, struct logical_volume *lv,
return 0;
}
/*
* If the LV is locked from activation, this lock call is a no-op.
* Otherwise, this acquires a transient lock on the lv (not PERSISTENT).
*/
if (!lockd_lv(cmd, lv, "ex", 0))
return_0;
if (lp->sizeargs &&
!(lock_lv = _lvresize_volume(cmd, lv, lp, pvh)))
return_0;
@@ -5574,6 +5606,7 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
int format1_reload_required = 0;
int visible;
struct logical_volume *pool_lv = NULL;
struct logical_volume *lock_lv = lv;
struct lv_segment *cache_seg = NULL;
int ask_discard;
struct lv_list *lvl;
@@ -5620,14 +5653,19 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
log_error("Can't remove logical volume %s used by a pool.",
lv->name);
return 0;
} else if (lv_is_thin_volume(lv))
} else if (lv_is_thin_volume(lv)) {
pool_lv = first_seg(lv)->pool_lv;
lock_lv = pool_lv;
}
if (lv_is_locked(lv)) {
log_error("Can't remove locked LV %s", lv->name);
return 0;
}
if (!lockd_lv(cmd, lock_lv, "ex", LDLV_PERSISTENT))
return_0;
/* FIXME Ensure not referred to by another existing LVs */
ask_discard = find_config_tree_bool(cmd, devices_issue_discards_CFG, NULL);
@@ -5802,6 +5840,9 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
backup(vg);
lockd_lv(cmd, lock_lv, "un", LDLV_PERSISTENT);
lockd_free_lv(cmd, vg, lv->name, &lv->lvid.id[1], lv->lock_args);
if (!suppress_remove_message && visible)
log_print_unless_silent("Logical volume \"%s\" successfully removed", lv->name);
@@ -6128,7 +6169,7 @@ int remove_layers_for_segments(struct cmd_context *cmd,
log_error("Layer boundary mismatch: "
"%s:%" PRIu32 "-%" PRIu32 " on "
"%s:%" PRIu32 " / "
"%" PRIu32 "-%" PRIu32 " / ",
FMTu32 "-" FMTu32 " / ",
lv->name, seg->le, seg->area_len,
layer_lv->name, seg_le(seg, s),
lseg->le, lseg->area_len);
@@ -6621,7 +6662,12 @@ int wipe_lv(struct logical_volume *lv, struct wipe_params wp)
/* nothing to do */
return 1;
sync_local_dev_names(lv->vg->cmd); /* Wait until devices are available */
/* Wait until devices are available */
if (!sync_local_dev_names(lv->vg->cmd)) {
log_error("Failed to sync local devices before wiping LV %s.",
display_lvname(lv));
return 0;
}
if (!lv_is_active_locally(lv)) {
log_error("Volume \"%s/%s\" is not active locally.",
@@ -7184,6 +7230,14 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
lv->major, lv->minor);
}
/*
* The specific LV may not use a lock. lockd_init_lv() sets
* lv->lock_args to NULL if this LV does not use its own lock.
*/
if (!lockd_init_lv(vg->cmd, vg, lv, lp))
return_NULL;
dm_list_splice(&lv->tags, &lp->tags);
if (!lv_extend(lv, create_segtype,
@@ -7199,6 +7253,8 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
if (seg_is_cache_pool(lp) || seg_is_cache(lp)) {
pool_lv = pool_lv ? : lv;
if (!lv_cache_set_policy(pool_lv, lp->policy_name, lp->policy_settings))
return_NULL; /* revert? */
first_seg(pool_lv)->chunk_size = lp->chunk_size;
first_seg(pool_lv)->feature_flags = lp->feature_flags;
/* TODO: some calc_policy solution for cache ? */
@@ -7249,6 +7305,9 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
return_NULL;
}
if (!pool_check_overprovisioning(lv))
return_NULL;
/* FIXME Log allocation and attachment should have happened inside lv_extend. */
if (lp->log_count &&
!seg_is_raid(first_seg(lv)) && seg_is_mirrored(first_seg(lv))) {
@@ -7323,11 +7382,8 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
stack;
goto revert_new_lv;
}
/* When change is activating, don't duplicate backup call */
if (!is_change_activating(lp->activate))
backup(vg);
}
if (is_change_activating(lp->activate)) {
if (!dm_list_empty(&first_seg(pool_lv)->thin_messages)) {
/* Send message so that table preload knows new thin */
if (!lv_is_active(pool_lv)) {
/* Avoid multiple thin-pool activations in this case */
@@ -7345,25 +7401,24 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
}
}
/* Keep thin pool active until thin volume is activated */
if (!update_pool_lv(pool_lv, (thin_pool_was_active < 0) ? 1 : 0)) {
if (!update_pool_lv(pool_lv, 1)) {
stack;
goto revert_new_lv;
}
}
backup(vg);
backup(vg);
if (!lv_active_change(cmd, lv, lp->activate, 0)) {
log_error("Failed to activate thin %s.", lv->name);
goto deactivate_and_revert_new_lv;
}
if (!lv_active_change(cmd, lv, lp->activate, 0)) {
log_error("Failed to activate thin %s.", lv->name);
goto deactivate_and_revert_new_lv;
}
/* Restore inactive state if needed */
if (!thin_pool_was_active &&
!deactivate_lv(cmd, pool_lv)) {
log_error("Failed to deactivate thin pool %s.",
display_lvname(pool_lv));
return NULL;
}
/* Restore inactive state if needed */
if (!thin_pool_was_active &&
!deactivate_lv(cmd, pool_lv)) {
log_error("Failed to deactivate thin pool %s.",
display_lvname(pool_lv));
return NULL;
}
} else if (lp->snapshot) {
lv->status |= LV_TEMPORARY;
@@ -7392,13 +7447,6 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
}
}
if (lv_is_cache_pool(lv) && !origin_lv) {
if (lp->cache_policy && !lv_cache_setpolicy(lv, lp->cache_policy))
return NULL; /* revert? */
if (!lv_update_and_reload(lv))
return NULL; /* FIXME: revert */
}
if (seg_is_cache(lp) || (origin_lv && lv_is_cache_pool(lv))) {
/* Finish cache conversion magic */
if (origin_lv) {
@@ -7418,9 +7466,6 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
}
lv = tmp_lv;
if (lp->cache_policy && !lv_cache_setpolicy(lv, lp->cache_policy))
return NULL; /* revert? */
if (!lv_update_and_reload(lv)) {
/* FIXME Do a better revert */
log_error("Aborting. Manual intervention required.");
@@ -7434,6 +7479,13 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
goto deactivate_and_revert_new_lv; /* Let's retry on error path */
}
/* Get in sync with deactivation, before reusing LV as snapshot */
if (!sync_local_dev_names(lv->vg->cmd)) {
log_error("Failed to sync local devices before creating snapshot using %s.",
display_lvname(lv));
goto revert_new_lv;
}
/* Create zero origin volume for spare snapshot */
if (lp->virtual_extents &&
!(origin_lv = _create_virtual_origin(cmd, vg, lv->name,
@@ -7491,6 +7543,8 @@ deactivate_and_revert_new_lv:
}
revert_new_lv:
lockd_free_lv(vg->cmd, vg, lp->lv_name, &lv->lvid.id[1], lp->lock_args);
/* FIXME Better to revert to backup of metadata? */
if (!lv_remove(lv) || !vg_write(vg) || !vg_commit(vg))
log_error("Manual intervention may be required to remove "

View File

@@ -208,6 +208,12 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
}
}
if (seg_is_cache_pool(seg)) {
if (!seg->policy_name) {
log_error("LV %s is missing cache policy name.", lv->name);
inc_error_count;
}
}
if (seg_is_pool(seg)) {
if (seg->area_count != 1 ||
seg_type(seg, 0) != AREA_LV) {
@@ -231,8 +237,7 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
inc_error_count;
}
if (seg_is_pool(seg) &&
!validate_pool_chunk_size(lv->vg->cmd, seg->segtype, seg->chunk_size)) {
if (!validate_pool_chunk_size(lv->vg->cmd, seg->segtype, seg->chunk_size)) {
log_error("LV %s: %s segment %u has invalid chunk size %u.",
lv->name, seg->segtype->name, seg_count, seg->chunk_size);
inc_error_count;

View File

@@ -101,7 +101,6 @@
#define THIN_POOL_DATA UINT64_C(0x0000004000000000) /* LV - Internal use only */
#define THIN_POOL_METADATA UINT64_C(0x0000008000000000) /* LV - Internal use only */
#define POOL_METADATA_SPARE UINT64_C(0x0000010000000000) /* LV - Internal use only */
#define LV_WRITEMOSTLY UINT64_C(0x0000020000000000) /* LV (RAID1) */
#define LV_ACTIVATION_SKIP UINT64_C(0x0000040000000000) /* LV */
@@ -132,7 +131,8 @@
#define PV_ALLOCATION_PROHIBITED UINT64_C(0x0010000000000000) /* PV - internal use only - allocation prohibited
e.g. to prohibit allocation of a RAID image
on a PV already holing an image of the RAID set */
/* Next unused flag: UINT64_C(0x0080000000000000) */
#define LOCKD_SANLOCK_LV UINT64_C(0x0080000000000000) /* LV - Internal use only */
/* Next unused flag: UINT64_C(0x0100000000000000) */
/* Format features flags */
#define FMT_SEGMENTS 0x00000001U /* Arbitrary segment params? */
@@ -181,6 +181,7 @@
#define FAILED_RECOVERY 0x00000200U
#define FAILED_SYSTEMID 0x00000400U
#define FAILED_LOCK_TYPE 0x00000800U
#define FAILED_LOCK_MODE 0x00001000U
#define SUCCESS 0x00000000U
#define VGMETADATACOPIES_ALL UINT32_MAX
@@ -228,6 +229,7 @@
#define lv_is_pool_data(lv) (((lv)->status & (CACHE_POOL_DATA | THIN_POOL_DATA)) ? 1 : 0)
#define lv_is_pool_metadata(lv) (((lv)->status & (CACHE_POOL_METADATA | THIN_POOL_METADATA)) ? 1 : 0)
#define lv_is_pool_metadata_spare(lv) (((lv)->status & POOL_METADATA_SPARE) ? 1 : 0)
#define lv_is_lockd_sanlock_lv(lv) (((lv)->status & LOCKD_SANLOCK_LV) ? 1 : 0)
#define lv_is_rlog(lv) (((lv)->status & REPLICATOR_LOG) ? 1 : 0)
@@ -262,6 +264,14 @@ typedef enum {
THIN_DISCARDS_PASSDOWN,
} thin_discards_t;
typedef enum {
LOCK_TYPE_INVALID = -1,
LOCK_TYPE_NONE = 0,
LOCK_TYPE_CLVM = 1,
LOCK_TYPE_DLM = 2,
LOCK_TYPE_SANLOCK = 3,
} lock_type_t;
struct cmd_context;
struct format_handler;
struct labeller;
@@ -640,9 +650,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);
const char *vgid, uint32_t 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);
const char *vgid, uint32_t flags, uint32_t lockd_state);
/*
* Test validity of a VG handle.
@@ -685,6 +695,7 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name);
int vg_remove_mdas(struct volume_group *vg);
int vg_remove_check(struct volume_group *vg);
void vg_remove_pvs(struct volume_group *vg);
int vg_remove_direct(struct volume_group *vg);
int vg_remove(struct volume_group *vg);
int vg_rename(struct cmd_context *cmd, struct volume_group *vg,
const char *new_name);
@@ -738,6 +749,8 @@ int lv_empty(struct logical_volume *lv);
/* Empty an LV and add error segment */
int replace_lv_with_error_segment(struct logical_volume *lv);
int lv_refresh_suspend_resume(struct cmd_context *cmd, struct logical_volume *lv);
/* Entry point for all LV extent allocations */
int lv_extend(struct logical_volume *lv,
const struct segment_type *segtype,
@@ -828,7 +841,8 @@ typedef enum activation_change {
CHANGE_AEY = 2, /* activate exclusively */
CHANGE_ALY = 3, /* activate locally */
CHANGE_ALN = 4, /* deactivate locally */
CHANGE_AAY = 5 /* automatic activation */
CHANGE_AAY = 5, /* automatic activation */
CHANGE_ASY = 6 /* activate shared */
} activation_change_t;
/* Returns true, when change activates device */
@@ -860,12 +874,15 @@ struct lvcreate_params {
#define THIN_CHUNK_SIZE_CALC_METHOD_GENERIC 0x01
#define THIN_CHUNK_SIZE_CALC_METHOD_PERFORMANCE 0x02
int thin_chunk_size_calc_policy;
unsigned needs_lockd_init : 1;
const char *vg_name; /* only-used when VG is not yet opened (in /tools) */
const char *lv_name; /* all */
const char *origin_name; /* snap */
const char *pool_name; /* thin */
const char *lock_args;
/* Keep args given by the user on command line */
/* FIXME: create some more universal solution here */
#define PASS_ARG_CHUNK_SIZE 0x01
@@ -885,7 +902,8 @@ struct lvcreate_params {
uint32_t max_recovery_rate; /* RAID */
uint64_t feature_flags; /* cache */
struct dm_config_tree *cache_policy; /* cache */
const char *policy_name; /* cache */
struct dm_config_tree *policy_settings; /* cache */
const struct segment_type *segtype; /* all */
unsigned target_attr; /* all */
@@ -1147,7 +1165,8 @@ int validate_lv_cache_create_origin(const struct logical_volume *origin_lv);
struct logical_volume *lv_cache_create(struct logical_volume *pool,
struct logical_volume *origin);
int lv_cache_remove(struct logical_volume *cache_lv);
int lv_cache_setpolicy(struct logical_volume *cache_lv, struct dm_config_tree *pol);
int lv_cache_set_policy(struct logical_volume *cache_lv, const char *name,
const struct dm_config_tree *settings);
int wipe_cache_pool(struct logical_volume *cache_pool_lv);
/* -- metadata/cache_manip.c */
@@ -1208,6 +1227,8 @@ struct vgcreate_params {
int clustered; /* FIXME: put this into a 'status' variable instead? */
uint32_t vgmetadatacopies;
const char *system_id;
const char *lock_type;
const char *lock_args;
};
int validate_major_minor(const struct cmd_context *cmd,
@@ -1219,4 +1240,7 @@ int vgcreate_params_validate(struct cmd_context *cmd,
int validate_vg_rename_params(struct cmd_context *cmd,
const char *vg_name_old,
const char *vg_name_new);
int is_lockd_type(const char *lock_type);
#endif

View File

@@ -31,6 +31,7 @@
#include "locking.h"
#include "archiver.h"
#include "defaults.h"
#include "lvmlockd.h"
#include <math.h>
#include <sys/param.h>
@@ -557,20 +558,14 @@ void vg_remove_pvs(struct volume_group *vg)
}
}
int vg_remove(struct volume_group *vg)
int vg_remove_direct(struct volume_group *vg)
{
struct physical_volume *pv;
struct pv_list *pvl;
int ret = 1;
if (!lock_vol(vg->cmd, VG_ORPHANS, LCK_VG_WRITE, NULL)) {
log_error("Can't get lock for orphan PVs");
return 0;
}
if (!vg_remove_mdas(vg)) {
log_error("vg_remove_mdas %s failed", vg->name);
unlock_vg(vg->cmd, VG_ORPHANS);
return 0;
}
@@ -604,6 +599,8 @@ int vg_remove(struct volume_group *vg)
if (!lvmetad_vg_remove(vg))
stack;
lockd_vg_update(vg);
if (!backup_remove(vg->cmd, vg->name))
stack;
@@ -612,6 +609,20 @@ int vg_remove(struct volume_group *vg)
else
log_error("Volume group \"%s\" not properly removed", vg->name);
return ret;
}
int vg_remove(struct volume_group *vg)
{
int ret;
if (!lock_vol(vg->cmd, VG_ORPHANS, LCK_VG_WRITE, NULL)) {
log_error("Can't get lock for orphan PVs");
return 0;
}
ret = vg_remove_direct(vg);
unlock_vg(vg->cmd, VG_ORPHANS);
return ret;
}
@@ -2428,6 +2439,7 @@ struct validate_hash {
struct dm_hash_table *lvname;
struct dm_hash_table *lvid;
struct dm_hash_table *pvid;
struct dm_hash_table *lv_lock_args;
};
/*
@@ -2472,6 +2484,75 @@ static int _lv_validate_references_single(struct logical_volume *lv, void *data)
return r;
}
/*
* Format is <version>:<info>
*/
static int _validate_lock_args_chars(const char *lock_args)
{
int i;
char c;
int found_colon = 0;
int r = 1;
for (i = 0; i < strlen(lock_args); i++) {
c = lock_args[i];
if (!isalnum(c) && c != '.' && c != '_' && c != '-' && c != '+' && c != ':') {
log_error(INTERNAL_ERROR "Invalid character at index %d of lock_args \"%s\"",
i, lock_args);
r = 0;
}
if (c == ':' && found_colon) {
log_error(INTERNAL_ERROR "Invalid colon at index %d of lock_args \"%s\"",
i, lock_args);
r = 0;
}
if (c == ':')
found_colon = 1;
}
return r;
}
static int _validate_vg_lock_args(struct volume_group *vg)
{
if (!_validate_lock_args_chars(vg->lock_args)) {
log_error(INTERNAL_ERROR "VG %s has invalid lock_args chars", vg->name);
return 0;
}
return 1;
}
/*
* For lock_type sanlock, LV lock_args are <version>:<info>
* For lock_type dlm, LV lock_args are not used, and lock_args is
* just set to "dlm".
*/
static int _validate_lv_lock_args(struct logical_volume *lv)
{
int r = 1;
if (!strcmp(lv->vg->lock_type, "sanlock")) {
if (!_validate_lock_args_chars(lv->lock_args)) {
log_error(INTERNAL_ERROR "LV %s/%s has invalid lock_args chars",
lv->vg->name, display_lvname(lv));
return 0;
}
} else if (!strcmp(lv->vg->lock_type, "dlm")) {
if (strcmp(lv->lock_args, "dlm")) {
log_error(INTERNAL_ERROR "LV %s/%s has invalid lock_args \"%s\"",
lv->vg->name, display_lvname(lv), lv->lock_args);
r = 0;
}
}
return r;
}
int vg_validate(struct volume_group *vg)
{
struct pv_list *pvl;
@@ -2786,6 +2867,129 @@ int vg_validate(struct volume_group *vg)
if (vg_max_lv_reached(vg))
stack;
if (!(vhash.lv_lock_args = dm_hash_create(lv_count))) {
log_error("Failed to allocate lv_lock_args hash");
r = 0;
goto out;
}
if (is_lockd_type(vg->lock_type)) {
if (!vg->lock_args) {
log_error(INTERNAL_ERROR "VG %s with lock_type %s without lock_args",
vg->name, vg->lock_type);
r = 0;
}
if (vg_is_clustered(vg)) {
log_error(INTERNAL_ERROR "VG %s with lock_type %s is clustered",
vg->name, vg->lock_type);
r = 0;
}
if (vg->system_id && vg->system_id[0]) {
log_error(INTERNAL_ERROR "VG %s with lock_type %s has system_id %s",
vg->name, vg->lock_type, vg->system_id);
r = 0;
}
if (strcmp(vg->lock_type, "sanlock") && strcmp(vg->lock_type, "dlm")) {
log_error(INTERNAL_ERROR "VG %s has unknown lock_type %s",
vg->name, vg->lock_type);
r = 0;
}
if (!_validate_vg_lock_args(vg))
r = 0;
} else {
if (vg->lock_args) {
log_error(INTERNAL_ERROR "VG %s has lock_args %s without lock_type",
vg->name, vg->lock_args);
r = 0;
}
}
dm_list_iterate_items(lvl, &vg->lvs) {
if (is_lockd_type(vg->lock_type)) {
if (lockd_lv_uses_lock(lvl->lv)) {
if (vg->skip_validate_lock_args)
continue;
/*
* FIXME: make missing lock_args an error.
* There are at least two cases where this
* check doesn't work correctly:
*
* 1. When creating a cow snapshot,
* (lvcreate -s -L1M -n snap1 vg/lv1),
* lockd_lv_uses_lock() uses lv_is_cow()
* which depends on lv->snapshot being
* set, but it's not set at this point,
* so lockd_lv_uses_lock() cannot identify
* the LV as a cow_lv, and thinks it needs
* a lock when it doesn't. To fix this we
* probably need to validate by finding the
* origin LV, then finding all its snapshots
* which will have no lock_args.
*
* 2. When converting an LV to a thin pool
* without using an existing metadata LV,
* (lvconvert --type thin-pool vg/poolX),
* there is an intermediate LV created,
* probably for the metadata LV, and
* validate is called on the VG in this
* intermediate state, which finds the
* newly created LV which is not yet
* identified as a metadata LV, and
* does not have any lock_args. To fix
* this we might be able to find the place
* where the intermediate LV is created,
* and set new variable on it like for vgs,
* lv->skip_validate_lock_args.
*/
if (!lvl->lv->lock_args) {
/*
log_verbose("LV %s/%s missing lock_args",
vg->name, lvl->lv->name);
r = 0;
*/
continue;
}
if (!_validate_lv_lock_args(lvl->lv)) {
r = 0;
continue;
}
if (!strcmp(vg->lock_type, "sanlock")) {
if (dm_hash_lookup(vhash.lv_lock_args, lvl->lv->lock_args)) {
log_error(INTERNAL_ERROR "LV %s/%s has duplicate lock_args %s.",
vg->name, lvl->lv->name, lvl->lv->lock_args);
r = 0;
}
if (!dm_hash_insert(vhash.lv_lock_args, lvl->lv->lock_args, lvl)) {
log_error("Failed to hash lvname.");
r = 0;
}
}
} else {
if (lvl->lv->lock_args) {
log_error(INTERNAL_ERROR "LV %s/%s shouldn't have lock_args",
vg->name, lvl->lv->name);
r = 0;
}
}
} else {
if (lvl->lv->lock_args) {
log_error(INTERNAL_ERROR "LV %s/%s with no lock_type has lock_args %s",
vg->name, lvl->lv->name, lvl->lv->lock_args);
r = 0;
}
}
}
out:
if (vhash.lvid)
dm_hash_destroy(vhash.lvid);
@@ -2793,6 +2997,8 @@ out:
dm_hash_destroy(vhash.lvname);
if (vhash.pvid)
dm_hash_destroy(vhash.pvid);
if (vhash.lv_lock_args)
dm_hash_destroy(vhash.lv_lock_args);
return r;
}
@@ -2806,8 +3012,19 @@ int vg_write(struct volume_group *vg)
struct dm_list *mdah;
struct pv_to_create *pv_to_create;
struct metadata_area *mda;
struct lv_list *lvl;
int revert = 0, wrote = 0;
dm_list_iterate_items(lvl, &vg->lvs) {
if (lvl->lv->lock_args && !strcmp(lvl->lv->lock_args, "pending")) {
if (!lockd_init_lv_args(vg->cmd, vg, lvl->lv, vg->lock_type, &lvl->lv->lock_args)) {
log_error("Cannot allocate lock for new LV.");
return 0;
}
lvl->lv->new_lock_args = 1;
}
}
if (!vg_validate(vg))
return_0;
@@ -2974,6 +3191,8 @@ int vg_commit(struct volume_group *vg)
cache_updated = _vg_commit_mdas(vg);
lockd_vg_update(vg);
if (cache_updated) {
/* Instruct remote nodes to upgrade cached metadata. */
if (!remote_commit_cached_metadata(vg))
@@ -3007,6 +3226,14 @@ int vg_commit(struct volume_group *vg)
void vg_revert(struct volume_group *vg)
{
struct metadata_area *mda;
struct lv_list *lvl;
dm_list_iterate_items(lvl, &vg->lvs) {
if (lvl->lv->new_lock_args) {
lockd_free_lv(vg->cmd, vg, lvl->lv->name, &lvl->lv->lvid.id[1], lvl->lv->lock_args);
lvl->lv->new_lock_args = 0;
}
}
release_vg(vg->vg_precommitted); /* VG is no longer needed */
vg->vg_precommitted = NULL;
@@ -3224,6 +3451,33 @@ static int _check_mda_in_use(struct metadata_area *mda, void *_in_use)
return 1;
}
static int _wipe_outdated_pvs(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *to_check)
{
struct pv_list *pvl, *pvl2;
char uuid[64] __attribute__((aligned(8)));
dm_list_iterate_items(pvl, to_check) {
dm_list_iterate_items(pvl2, &vg->pvs) {
if (pvl->pv->dev == pvl2->pv->dev)
goto next_pv;
}
if (!id_write_format(&pvl->pv->id, uuid, sizeof(uuid)))
return_0;
log_warn("WARNING: Removing PV %s (%s) that no longer belongs to VG %s",
pv_dev_name(pvl->pv), uuid, vg->name);
if (!pv_write_orphan(cmd, pvl->pv))
return_0;
/* Refresh metadata after orphan write */
if (!drop_cached_metadata(vg)) {
log_error("Unable to drop cached metadata for VG %s while wiping outdated PVs.", vg->name);
return 0;
}
next_pv:
;
}
return 1;
}
/* Caller sets consistent to 1 if it's safe for vg_read_internal to correct
* inconsistent metadata on disk (i.e. the VG write lock is held).
* This guarantees only consistent metadata is returned.
@@ -3257,9 +3511,8 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
int inconsistent_mda_count = 0;
unsigned use_precommitted = precommitted;
struct dm_list *pvids;
struct pv_list *pvl, *pvl2;
struct pv_list *pvl;
struct dm_list all_pvs;
char uuid[64] __attribute__((aligned(8)));
unsigned seqno = 0;
int reappeared = 0;
struct cached_vg_fmtdata *vg_fmtdata = NULL; /* Additional format-specific data about the vg */
@@ -3284,6 +3537,11 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
*consistent = _repair_inconsistent_vg(correct_vg);
else
*consistent = !reappeared;
if (_wipe_outdated_pvs(cmd, correct_vg, &correct_vg->pvs_outdated)) {
/* clear the list */
dm_list_init(&correct_vg->pvs_outdated);
lvmetad_vg_clear_outdated_pvs(correct_vg);
}
}
return correct_vg;
}
@@ -3684,28 +3942,10 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
return NULL;
}
dm_list_iterate_items(pvl, &all_pvs) {
dm_list_iterate_items(pvl2, &correct_vg->pvs) {
if (pvl->pv->dev == pvl2->pv->dev)
goto next_pv;
}
if (!id_write_format(&pvl->pv->id, uuid, sizeof(uuid))) {
_free_pv_list(&all_pvs);
release_vg(correct_vg);
return_NULL;
}
log_warn("WARNING: Removing PV %s (%s) that no longer belongs to VG %s",
pv_dev_name(pvl->pv), uuid, correct_vg->name);
if (!pv_write_orphan(cmd, pvl->pv)) {
_free_pv_list(&all_pvs);
release_vg(correct_vg);
return_NULL;
}
/* Refresh metadata after orphan write */
drop_cached_metadata(correct_vg);
next_pv:
;
if (!_wipe_outdated_pvs(cmd, correct_vg, &all_pvs)) {
_free_pv_list(&all_pvs);
release_vg(correct_vg);
return_NULL;
}
}
@@ -3808,6 +4048,16 @@ static struct volume_group *_vg_read_by_vgid(struct cmd_context *cmd,
release_vg(vg);
}
/*
* When using lvmlockd we should never reach this point.
* The VG is locked, then vg_read() is done, which gets
* the latest VG from lvmetad, or disk if lvmetad has
* been invalidated. When we get here the VG should
* always be cached and returned above.
*/
if (lvmlockd_use())
log_error(INTERNAL_ERROR "vg_read_by_vgid failed with lvmlockd");
/* Mustn't scan if memory locked: ensure cache gets pre-populated! */
if (critical_section())
return_NULL;
@@ -4457,13 +4707,13 @@ static struct volume_group *_recover_vg(struct cmd_context *cmd,
return (struct volume_group *)vg;
}
static int _allow_system_id(struct cmd_context *cmd, const char *system_id)
static int _allow_extra_system_id(struct cmd_context *cmd, const char *system_id)
{
const struct dm_config_node *cn;
const struct dm_config_value *cv;
const char *str;
if (!(cn = find_config_tree_node(cmd, local_extra_system_ids_CFG, NULL)))
if (!(cn = find_config_tree_array(cmd, local_extra_system_ids_CFG, NULL)))
return 0;
for (cv = cn->v; cv; cv = cv->next) {
@@ -4496,20 +4746,73 @@ static int _access_vg_clustered(struct cmd_context *cmd, struct volume_group *vg
return 1;
}
static int _access_vg_lock_type(struct cmd_context *cmd, struct volume_group *vg)
static int _access_vg_lock_type(struct cmd_context *cmd, struct volume_group *vg,
uint32_t lockd_state, uint32_t *failure)
{
if (!is_real_vg(vg->name))
return 1;
if (cmd->lockd_vg_disable)
return 1;
/*
* Until lock_type support is added, reject any VG that has a lock_type.
* Local VG requires no lock from lvmlockd.
*/
if (vg->lock_type && vg->lock_type[0] && strcmp(vg->lock_type, "none")) {
log_error("Cannot access VG %s with unsupported lock_type %s.",
vg->name, vg->lock_type);
if (!is_lockd_type(vg->lock_type))
return 1;
/*
* When lvmlockd is not used, lockd VGs are ignored by lvm
* and cannot be used, with two exceptions:
*
* . The --shared option allows them to be revealed with
* reporting/display commands.
*
* . If a command asks to operate on one specifically
* by name, then an error is printed.
*/
if (!lvmlockd_use()) {
/*
* Some reporting/display commands have the --shared option
* (like --foreign) to allow them to reveal lockd VGs that
* are otherwise ignored. The --shared option must only be
* permitted in commands that read the VG for report or display,
* not any that write the VG or activate LVs.
*/
if (cmd->include_shared_vgs)
return 1;
/*
* Some commands want the error printed by vg_read, others by ignore_vg.
* Those using ignore_vg may choose to skip the error.
*/
if (cmd->vg_read_print_access_error) {
log_error("Cannot access VG %s with lock type %s that requires lvmlockd.",
vg->name, vg->lock_type);
}
*failure |= FAILED_LOCK_TYPE;
return 0;
}
/*
* The lock request from lvmlockd failed. If the lock was ex,
* we cannot continue. If the lock was sh, we could also fail
* to continue but since the lock was sh, it means the VG is
* only being read, and it doesn't hurt to allow reading with
* no lock.
*/
if (lockd_state & LDST_FAIL) {
if ((lockd_state & LDST_EX) || cmd->lockd_vg_enforce_sh) {
log_error("Cannot access VG %s due to failed lock.", vg->name);
*failure |= FAILED_LOCK_MODE;
return 0;
} else {
log_warn("Reading VG %s without a lock.", vg->name);
return 1;
}
}
return 1;
}
@@ -4545,7 +4848,7 @@ static int _access_vg_systemid(struct cmd_context *cmd, struct volume_group *vg)
/*
* A host can access a VG if the VG's system_id is in extra_system_ids list.
*/
if (cmd->system_id && _allow_system_id(cmd, vg->system_id))
if (cmd->system_id && _allow_extra_system_id(cmd, vg->system_id))
return 1;
/*
@@ -4569,18 +4872,16 @@ static int _access_vg_systemid(struct cmd_context *cmd, struct volume_group *vg)
}
/*
* Some commands always produce an error when accessing foreign VG.
* Some commands want the error printed by vg_read, others by ignore_vg.
* Those using ignore_vg may choose to skip the error.
*/
if (cmd->error_foreign_vgs) {
if (cmd->vg_read_print_access_error) {
log_error("Cannot access VG %s with system ID %s with local system ID %s.",
vg->name, vg->system_id, cmd->system_id);
return 0;
}
/*
* When include_foreign_vgs is 0 and error_foreign_vgs is 0,
* the result is to silently ignore foreign vgs.
*/
/* Silently ignore foreign vgs. */
return 0;
}
@@ -4588,7 +4889,8 @@ static int _access_vg_systemid(struct cmd_context *cmd, struct volume_group *vg)
/*
* FIXME: move _vg_bad_status_bits() checks in here.
*/
static int _vg_access_permitted(struct cmd_context *cmd, struct volume_group *vg, uint32_t *failure)
static int _vg_access_permitted(struct cmd_context *cmd, struct volume_group *vg,
uint32_t lockd_state, uint32_t *failure)
{
if (!is_real_vg(vg->name)) {
/* Disallow use of LVM1 orphans when a host system ID is set. */
@@ -4604,8 +4906,8 @@ static int _vg_access_permitted(struct cmd_context *cmd, struct volume_group *vg
return 0;
}
if (!_access_vg_lock_type(cmd, vg)) {
*failure |= FAILED_LOCK_TYPE;
if (!_access_vg_lock_type(cmd, vg, lockd_state, failure)) {
/* Either FAILED_LOCK_TYPE or FAILED_LOCK_MODE were set. */
return 0;
}
@@ -4630,7 +4932,8 @@ static int _vg_access_permitted(struct cmd_context *cmd, struct volume_group *vg
*/
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)
uint64_t status_flags, uint32_t misc_flags,
uint32_t lockd_state)
{
struct volume_group *vg = NULL;
int consistent = 1;
@@ -4676,7 +4979,7 @@ static struct volume_group *_vg_lock_and_read(struct cmd_context *cmd, const cha
goto bad;
}
if (!_vg_access_permitted(cmd, vg, &failure))
if (!_vg_access_permitted(cmd, vg, lockd_state, &failure))
goto bad;
/* consistent == 0 when VG is not found, but failed == FAILED_NOTFOUND */
@@ -4752,7 +5055,7 @@ bad_no_unlock:
* *consistent = 1.
*/
struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,
const char *vgid, uint32_t flags)
const char *vgid, uint32_t flags, uint32_t lockd_state)
{
uint64_t status = UINT64_C(0);
uint32_t lock_flags = LCK_VG_READ;
@@ -4765,7 +5068,7 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,
if (flags & READ_ALLOW_EXPORTED)
status &= ~EXPORTED_VG;
return _vg_lock_and_read(cmd, vg_name, vgid, lock_flags, status, flags);
return _vg_lock_and_read(cmd, vg_name, vgid, lock_flags, status, flags, lockd_state);
}
/*
@@ -4774,9 +5077,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)
const char *vgid, uint32_t flags, uint32_t lockd_state)
{
return vg_read(cmd, vg_name, vgid, flags | READ_FOR_UPDATE);
return vg_read(cmd, vg_name, vgid, flags | READ_FOR_UPDATE, lockd_state);
}
/*
@@ -5208,3 +5511,21 @@ const struct logical_volume *lv_ondisk(const struct logical_volume *lv)
return lvl->lv;
}
/*
* Check if a lock_type uses lvmlockd.
* If not (none, clvm), return 0.
* If so (dlm, sanlock), return 1.
*/
int is_lockd_type(const char *lock_type)
{
if (!lock_type)
return 0;
if (!strcmp(lock_type, "dlm"))
return 1;
if (!strcmp(lock_type, "sanlock"))
return 1;
return 0;
}

View File

@@ -460,6 +460,8 @@ struct volume_group *import_vg_from_buffer(const char *buf,
struct format_instance *fid);
struct volume_group *import_vg_from_config_tree(const struct dm_config_tree *cft,
struct format_instance *fid);
struct volume_group *import_vg_from_lvmetad_config_tree(const struct dm_config_tree *cft,
struct format_instance *fid);
/*
* Mirroring functions
@@ -483,6 +485,7 @@ int lv_is_merging_thin_snapshot(const struct logical_volume *lv);
int pool_has_message(const struct lv_segment *seg,
const struct logical_volume *lv, uint32_t device_id);
int pool_below_threshold(const struct lv_segment *pool_seg);
int pool_check_overprovisioning(const struct logical_volume *lv);
int create_pool(struct logical_volume *lv, const struct segment_type *segtype,
struct alloc_handle *ah, uint32_t stripes, uint32_t stripe_size);

View File

@@ -368,7 +368,11 @@ static int _init_mirror_log(struct cmd_context *cmd,
backup(log_lv->vg);
/* Wait for events following any deactivation before reactivating */
sync_local_dev_names(cmd);
if (!sync_local_dev_names(cmd)) {
log_error("Aborting. Failed to sync local devices before initialising mirror log %s.",
display_lvname(log_lv));
goto revert_new_lv;
}
if (!activate_lv(cmd, log_lv)) {
log_error("Aborting. Failed to activate mirror log.");
@@ -484,7 +488,11 @@ static int _delete_lv(struct logical_volume *mirror_lv, struct logical_volume *l
return_0;
/* FIXME Is this superfluous now? */
sync_local_dev_names(cmd);
if (!sync_local_dev_names(cmd)) {
log_error("Failed to sync local devices when reactivating %s.",
display_lvname(lv));
return 0;
}
if (!deactivate_lv(cmd, lv))
return_0;
@@ -1163,7 +1171,7 @@ static int _remove_mirror_images(struct logical_volume *lv,
if (removed)
*removed = old_area_count - new_area_count;
log_very_verbose("%" PRIu32 " image(s) removed from %s",
log_very_verbose(FMTu32 " image(s) removed from %s",
old_area_count - new_area_count, lv->name);
return 1;

View File

@@ -21,6 +21,7 @@
#include "activate.h"
#include "lv_alloc.h"
#include "lvm-string.h"
#include "lvmlockd.h"
static int _lv_is_raid_with_tracking(const struct logical_volume *lv,
struct logical_volume **tracking)
@@ -1007,10 +1008,15 @@ static int _raid_remove_images(struct logical_volume *lv,
return 0;
}
if (!sync_local_dev_names(lv->vg->cmd)) {
log_error("Failed to sync local devices after committing changes for %s.",
display_lvname(lv));
return 0;
}
/*
* Eliminate the extracted LVs
*/
sync_local_dev_names(lv->vg->cmd);
if (!dm_list_empty(&removal_list)) {
dm_list_iterate_items(lvl, &removal_list) {
if (!deactivate_lv(lv->vg->cmd, lvl->lv))
@@ -1082,6 +1088,12 @@ int lv_raid_split(struct logical_volume *lv, const char *split_name,
dm_list_init(&removal_list);
dm_list_init(&data_list);
if (is_lockd_type(lv->vg->lock_type)) {
log_error("Splitting raid image is not allowed with lock_type %s",
lv->vg->lock_type);
return 0;
}
if ((old_count - new_count) != 1) {
log_error("Unable to split more than one image from %s/%s",
lv->vg->name, lv->name);

View File

@@ -298,7 +298,7 @@ int check_replicator_segment(const struct lv_segment *rseg)
}
if (rsite->fall_behind_data) {
log_error("Defined fall_behind_data="
"%" PRIu64 " for sync replicator %s/%s.",
FMTu64 " for sync replicator %s/%s.",
rsite->fall_behind_data, lv->name, rsite->name);
r = 0;
}
@@ -566,7 +566,7 @@ int cmd_vg_read(struct cmd_context *cmd, struct dm_list *cmd_vgs)
/* Iterate through alphabeticaly ordered cmd_vg list */
dm_list_iterate_items(cvl, cmd_vgs) {
cvl->vg = vg_read(cmd, cvl->vg_name, cvl->vgid, cvl->flags);
cvl->vg = vg_read(cmd, cvl->vg_name, cvl->vgid, cvl->flags, 0);
if (vg_read_error(cvl->vg)) {
log_debug_metadata("Failed to vg_read %s", cvl->vg_name);
return 0;
@@ -644,7 +644,7 @@ int lv_read_replicator_vgs(const struct logical_volume *lv)
dm_list_iterate_items(rsite, &first_seg(lv)->replicator->rsites) {
if (!rsite->vg_name)
continue;
vg = vg_read(lv->vg->cmd, rsite->vg_name, 0, 0); // READ_WITHOUT_LOCK
vg = vg_read(lv->vg->cmd, rsite->vg_name, 0, 0, 0); // READ_WITHOUT_LOCK
if (vg_read_error(vg)) {
log_error("Unable to read volume group %s",
rsite->vg_name);

View File

@@ -21,6 +21,7 @@
#include "defaults.h"
#include "display.h"
/* TODO: drop unused no_update */
int attach_pool_message(struct lv_segment *pool_seg, dm_thin_message_t type,
struct logical_volume *lv, uint32_t delete_id,
int no_update)
@@ -62,10 +63,6 @@ int attach_pool_message(struct lv_segment *pool_seg, dm_thin_message_t type,
tmsg->type = type;
/* If the 1st message is add in non-read-only mode, modify transaction_id */
if (!no_update && dm_list_empty(&pool_seg->thin_messages))
pool_seg->transaction_id++;
dm_list_add(&pool_seg->thin_messages, &tmsg->list);
log_debug_metadata("Added %s message.",
@@ -236,6 +233,96 @@ int pool_below_threshold(const struct lv_segment *pool_seg)
return 1;
}
/*
* Detect overprovisioning and check lvm2 is configured for auto resize.
*
* If passed LV is thin volume/pool, check first only this one for overprovisiong.
* Lots of test combined together.
* Test is not detecting status of dmeventd, too complex for now...
*/
int pool_check_overprovisioning(const struct logical_volume *lv)
{
const struct lv_list *lvl;
const struct seg_list *sl;
const struct logical_volume *pool_lv = NULL;
struct cmd_context *cmd = lv->vg->cmd;
const char *txt = "";
uint64_t thinsum = 0, poolsum = 0, sz = ~0;
int threshold, max_threshold = 0;
int percent, min_percent = 100;
int more_pools = 0;
/* When passed thin volume, check related pool first */
if (lv_is_thin_volume(lv))
pool_lv = first_seg(lv)->pool_lv;
else if (lv_is_thin_pool(lv))
pool_lv = lv;
if (pool_lv) {
poolsum += pool_lv->size;
dm_list_iterate_items(sl, &pool_lv->segs_using_this_lv)
thinsum += sl->seg->lv->size;
if (thinsum <= poolsum)
return 1; /* All thins fit into this thin pool */
}
/* Sum all thins and all thin pools in VG */
dm_list_iterate_items(lvl, &lv->vg->lvs) {
if (!lv_is_thin_pool(lvl->lv))
continue;
threshold = find_config_tree_int(cmd, activation_thin_pool_autoextend_threshold_CFG,
lv_config_profile(lvl->lv));
percent = find_config_tree_int(cmd, activation_thin_pool_autoextend_percent_CFG,
lv_config_profile(lvl->lv));
if (threshold > max_threshold)
max_threshold = threshold;
if (percent < min_percent)
min_percent = percent;
if (lvl->lv == pool_lv)
continue; /* Skip iteration for already checked thin pool */
more_pools++;
poolsum += lvl->lv->size;
dm_list_iterate_items(sl, &lvl->lv->segs_using_this_lv)
thinsum += sl->seg->lv->size;
}
if (thinsum <= poolsum)
return 1; /* All fits for all pools */
if ((sz = vg_size(lv->vg)) < thinsum)
/* Thin sum size is above VG size */
txt = " and the size of whole volume group";
else if ((sz = vg_free(lv->vg)) < thinsum)
/* Thin sum size is more then free space in a VG */
txt = !sz ? "" : " and the amount of free space in volume group";
else if ((max_threshold > 99) || !min_percent)
/* There is some free space in VG, but it is not configured
* for growing - threshold is 100% or percent is 0% */
sz = poolsum;
else
sz = ~0; /* No warning */
if (sz != ~0) {
log_warn("WARNING: Sum of all thin volume sizes (%s) exceeds the "
"size of thin pool%s%s%s (%s)!",
display_size(cmd, thinsum),
more_pools ? "" : " ",
more_pools ? "s" : display_lvname(pool_lv),
txt,
(sz > 0) ? display_size(cmd, sz) : "no free space in volume group");
if (max_threshold > 99)
log_print_unless_silent("For thin pool auto extension activation/thin_pool_autoextend_threshold should be below 100.");
if (!min_percent)
log_print_unless_silent("For thin pool auto extension activation/thin_pool_autoextend_percent should be above 0.");
}
return 1;
}
/*
* Validate given external origin could be used with thin pool
*/
@@ -243,12 +330,11 @@ int pool_supports_external_origin(const struct lv_segment *pool_seg, const struc
{
uint32_t csize = pool_seg->chunk_size;
if ((external_lv->size < csize) || (external_lv->size % csize)) {
/* TODO: Validate with thin feature flag once, it will be supported */
log_error("Can't use \"%s/%s\" as external origin with \"%s/%s\" pool. "
if (((external_lv->size < csize) || (external_lv->size % csize)) &&
!thin_pool_feature_supported(pool_seg->lv, THIN_FEATURE_EXTERNAL_ORIGIN_EXTEND)) {
log_error("Can't use \"%s\" as external origin with \"%s\" pool. "
"Size %s is not a multiple of pool's chunk size %s.",
external_lv->vg->name, external_lv->name,
pool_seg->lv->vg->name, pool_seg->lv->name,
display_lvname(external_lv), display_lvname(pool_seg->lv),
display_size(external_lv->vg->cmd, external_lv->size),
display_size(external_lv->vg->cmd, csize));
return 0;
@@ -336,7 +422,7 @@ static int _check_pool_create(const struct logical_volume *lv)
int update_pool_lv(struct logical_volume *lv, int activate)
{
int monitored;
int monitored = DMEVENTD_MONITOR_IGNORE;
int ret = 1;
if (!lv_is_thin_pool(lv)) {
@@ -362,32 +448,37 @@ int update_pool_lv(struct logical_volume *lv, int activate)
display_lvname(lv));
return 0;
}
} else
activate = 0; /* Was already active */
if (!(ret = _check_pool_create(lv)))
stack;
if (!(ret = _check_pool_create(lv)))
stack; /* Safety guard, needs local presence of thin-pool target */
else if (!(ret = suspend_lv_origin(lv->vg->cmd, lv)))
/* Send messages */
log_error("Failed to suspend and send message %s.", display_lvname(lv));
else if (!(ret = resume_lv_origin(lv->vg->cmd, lv)))
log_error("Failed to resume %s.", display_lvname(lv));
if (activate) {
if (!deactivate_lv(lv->vg->cmd, lv)) {
init_dmeventd_monitor(monitored);
return_0;
}
init_dmeventd_monitor(monitored);
/* Unlock memory if possible */
memlock_unlock(lv->vg->cmd);
}
/*
* Resume active pool to send thin messages.
* origin_only is used to skip check for resumed state
*/
else if (!resume_lv_origin(lv->vg->cmd, lv)) {
log_error("Failed to resume %s.", lv->name);
return 0;
} else if (!(ret = _check_pool_create(lv)))
stack;
/* Unlock memory if possible */
memlock_unlock(lv->vg->cmd);
if (!ret)
return_0;
}
dm_list_init(&(first_seg(lv)->thin_messages));
/* thin-pool target transaction is finished, increase lvm2 TID */
first_seg(lv)->transaction_id++;
if (!vg_write(lv->vg) || !vg_commit(lv->vg))
return_0;
@@ -631,7 +722,7 @@ int check_new_thin_pool(const struct logical_volume *pool_lv)
/* Require pool to have same transaction_id as new */
if (first_seg(pool_lv)->transaction_id != transaction_id) {
log_error("Cannot use thin pool %s with transaction id "
"%" PRIu64 " for thin volumes. "
FMTu64 " for thin volumes. "
"Expected transaction id %" PRIu64 ".",
display_lvname(pool_lv), transaction_id,
first_seg(pool_lv)->transaction_id);

View File

@@ -20,6 +20,7 @@
#include "toolcontext.h"
#include "lvmcache.h"
#include "archiver.h"
#include "lvmlockd.h"
struct volume_group *alloc_vg(const char *pool_name, struct cmd_context *cmd,
const char *vg_name)
@@ -61,6 +62,7 @@ struct volume_group *alloc_vg(const char *pool_name, struct cmd_context *cmd,
dm_list_init(&vg->pvs);
dm_list_init(&vg->pvs_to_create);
dm_list_init(&vg->pvs_outdated);
dm_list_init(&vg->lvs);
dm_list_init(&vg->tags);
dm_list_init(&vg->removed_lvs);
@@ -133,6 +135,16 @@ char *vg_system_id_dup(const struct volume_group *vg)
return dm_pool_strdup(vg->vgmem, vg->system_id ? : vg->lvm1_system_id ? : "");
}
char *vg_lock_type_dup(const struct volume_group *vg)
{
return dm_pool_strdup(vg->vgmem, vg->lock_type ? : vg->lock_type ? : "");
}
char *vg_lock_args_dup(const struct volume_group *vg)
{
return dm_pool_strdup(vg->vgmem, vg->lock_args ? : vg->lock_args ? : "");
}
char *vg_uuid_dup(const struct volume_group *vg)
{
return id_format_and_copy(vg->vgmem, &vg->id);
@@ -636,6 +648,19 @@ int vg_set_system_id(struct volume_group *vg, const char *system_id)
return 1;
}
int vg_set_lock_type(struct volume_group *vg, const char *lock_type)
{
if (!lock_type)
lock_type = "none";
if (!(vg->lock_type = dm_pool_strdup(vg->vgmem, lock_type))) {
log_error("vg_set_lock_type %s no mem", lock_type);
return 0;
}
return 1;
}
char *vg_attr_dup(struct dm_pool *mem, const struct volume_group *vg)
{
char *repstr;
@@ -650,7 +675,14 @@ char *vg_attr_dup(struct dm_pool *mem, const struct volume_group *vg)
repstr[2] = (vg_is_exported(vg)) ? 'x' : '-';
repstr[3] = (vg_missing_pv_count(vg)) ? 'p' : '-';
repstr[4] = alloc_policy_char(vg->alloc);
repstr[5] = (vg_is_clustered(vg)) ? 'c' : '-';
if (vg_is_clustered(vg))
repstr[5] = 'c';
else if (is_lockd_type(vg->lock_type))
repstr[5] = 's';
else
repstr[5] = '-';
return repstr;
}
@@ -705,7 +737,7 @@ int vgreduce_single(struct cmd_context *cmd, struct volume_group *vg,
vg->extent_count -= pv_pe_count(pv);
orphan_vg = vg_read_for_update(cmd, vg->fid->fmt->orphan_vg_name,
NULL, 0);
NULL, 0, 0);
if (vg_read_error(orphan_vg))
goto bad;

View File

@@ -49,6 +49,7 @@ struct volume_group {
struct dm_list *cmd_vgs;/* List of wanted/locked and opened VGs */
uint32_t cmd_missing_vgs;/* Flag marks missing VG */
uint32_t seqno; /* Metadata sequence number */
unsigned skip_validate_lock_args : 1;
/*
* The parsed on-disk copy of this VG; is NULL if this is the on-disk
@@ -71,6 +72,7 @@ struct volume_group {
const char *system_id;
char *lvm1_system_id;
const char *lock_type;
const char *lock_args;
uint32_t extent_size;
uint32_t extent_count;
@@ -90,6 +92,24 @@ struct volume_group {
struct dm_list pvs_to_create;
/*
* List of physical volumes that carry outdated metadata that belongs
* to this VG. Currently only populated when lvmetad is in use. The PVs
* on this list could still belong to the VG (but their MDA carries an
* out-of-date copy of the VG metadata) or they could no longer belong
* to the VG. With lvmetad, this list is populated with all PVs that
* have a VGID matching ours, but seqno that is smaller than the
* current seqno for the VG. The MDAs on still-in-VG PVs are updated as
* part of the normal vg_write/vg_commit process. The MDAs on PVs that
* no longer belong to the VG are wiped during vg_read.
*
* However, even though still-in-VG PVs *may* be on the list, this is
* not guaranteed. The in-lvmetad list is cleared whenever out-of-VG
* outdated PVs are wiped during vg_read.
*/
struct dm_list pvs_outdated;
/*
* logical volumes
* The following relationship should always hold:
@@ -133,6 +153,7 @@ struct volume_group {
struct dm_hash_table *hostnames; /* map of creation hostnames */
struct logical_volume *pool_metadata_spare_lv; /* one per VG */
struct logical_volume *sanlock_lv; /* one per VG */
};
struct volume_group *alloc_vg(const char *pool_name, struct cmd_context *cmd,
@@ -148,11 +169,14 @@ void free_orphan_vg(struct volume_group *vg);
char *vg_fmt_dup(const struct volume_group *vg);
char *vg_name_dup(const struct volume_group *vg);
char *vg_system_id_dup(const struct volume_group *vg);
char *vg_lock_type_dup(const struct volume_group *vg);
char *vg_lock_args_dup(const struct volume_group *vg);
uint32_t vg_seqno(const struct volume_group *vg);
uint64_t vg_status(const struct volume_group *vg);
int vg_set_alloc_policy(struct volume_group *vg, alloc_policy_t alloc);
int vg_set_clustered(struct volume_group *vg, int clustered);
int vg_set_system_id(struct volume_group *vg, const char *system_id);
int vg_set_lock_type(struct volume_group *vg, const char *lock_type);
uint64_t vg_size(const struct volume_group *vg);
uint64_t vg_free(const struct volume_group *vg);
uint64_t vg_extent_size(const struct volume_group *vg);

View File

@@ -195,7 +195,7 @@ static int _mirrored_target_percent(void **target_state,
pos += used;
}
if (sscanf(pos, "%" PRIu64 "/%" PRIu64 "%n", &numerator, &denominator,
if (sscanf(pos, FMTu64 "/" FMTu64 "%n", &numerator, &denominator,
&used) != 2) {
log_error("Failure parsing mirror status fraction: %s", params);
return 0;

1
lib/misc/.gitignore vendored
View File

@@ -1 +1,2 @@
configure.h
lvm-version.h

View File

@@ -6,6 +6,10 @@
/* The path to 'cache_check', if available. */
#undef CACHE_CHECK_CMD
/* Define to 1 if the external 'cache_check' tool requires the
--clear-needs-check-flag option */
#undef CACHE_CHECK_NEEDS_CHECK
/* The path to 'cache_dump', if available. */
#undef CACHE_DUMP_CMD
@@ -68,6 +72,10 @@
/* Default system configuration directory. */
#undef DEFAULT_ETC_DIR
/* Fall back to LVM1 by default if device-mapper is missing from the kernel.
*/
#undef DEFAULT_FALLBACK_TO_LVM1
/* Name of default locking directory. */
#undef DEFAULT_LOCK_DIR
@@ -95,9 +103,15 @@
/* Path to LVM system directory. */
#undef DEFAULT_SYS_DIR
/* Use blkid wiping by default. */
#undef DEFAULT_USE_BLKID_WIPING
/* Use lvmetad by default. */
#undef DEFAULT_USE_LVMETAD
/* Use lvmlockd by default. */
#undef DEFAULT_USE_LVMLOCKD
/* Use lvmpolld by default. */
#undef DEFAULT_USE_LVMPOLLD
@@ -113,9 +127,27 @@
/* Path to dmeventd pidfile. */
#undef DMEVENTD_PIDFILE
/* Define to enable compat protocol */
#undef DM_COMPAT
/* Define default group for device node */
#undef DM_DEVICE_GID
/* Define default mode for device node */
#undef DM_DEVICE_MODE
/* Define default owner for device node */
#undef DM_DEVICE_UID
/* Define to enable ioctls calls to kernel */
#undef DM_IOCTLS
/* Library version */
#undef DM_LIB_VERSION
/* Define to 1 if you have the `alarm' function. */
#undef HAVE_ALARM
/* Define to 1 if you have `alloca', as a function or macro. */
#undef HAVE_ALLOCA
@@ -132,12 +164,18 @@
/* Define to 1 if you have the <assert.h> header file. */
#undef HAVE_ASSERT_H
/* Define to 1 if you have the `atexit' function. */
#undef HAVE_ATEXIT
/* Define to 1 if canonicalize_file_name is available. */
#undef HAVE_CANONICALIZE_FILE_NAME
/* Define to 1 if your system has a working `chown' function. */
#undef HAVE_CHOWN
/* Define to 1 if you have the `clock_gettime' function. */
#undef HAVE_CLOCK_GETTIME
/* Define to 1 if you have the <corosync/cmap.h> header file. */
#undef HAVE_COROSYNC_CMAP_H
@@ -147,6 +185,10 @@
/* Define to 1 if you have the <ctype.h> header file. */
#undef HAVE_CTYPE_H
/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you
don't. */
#undef HAVE_DECL_STRERROR_R
/* Define to 1 if you have the <dirent.h> header file. */
#undef HAVE_DIRENT_H
@@ -165,6 +207,9 @@
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
/* Define to 1 if you have the <float.h> header file. */
#undef HAVE_FLOAT_H
/* Define to 1 if you have the `fork' function. */
#undef HAVE_FORK
@@ -222,6 +267,9 @@
/* Define to 1 if you have the <locale.h> header file. */
#undef HAVE_LOCALE_H
/* Define to 1 if you have the `localtime_r' function. */
#undef HAVE_LOCALTIME_R
/* Define to 1 if `lstat' has the bug that it succeeds when given the
zero-length file name argument. */
#undef HAVE_LSTAT_EMPTY_STRING_BUG
@@ -236,6 +284,9 @@
/* Define to 1 if you have the <malloc.h> header file. */
#undef HAVE_MALLOC_H
/* Define to 1 if you have the `memchr' function. */
#undef HAVE_MEMCHR
/* Define to 1 if you have the `memmove' function. */
#undef HAVE_MEMMOVE
@@ -272,9 +323,15 @@
/* Define to 1 if you have the `nl_langinfo' function. */
#undef HAVE_NL_LANGINFO
/* Define to 1 if you have the <paths.h> header file. */
#undef HAVE_PATHS_H
/* Define to 1 if you have the <pthread.h> header file. */
#undef HAVE_PTHREAD_H
/* Define to 1 if the system has the type `ptrdiff_t'. */
#undef HAVE_PTRDIFF_T
/* Define to 1 if you have the <readline/history.h> header file. */
#undef HAVE_READLINE_HISTORY_H
@@ -285,6 +342,9 @@
and to 0 otherwise. */
#undef HAVE_REALLOC
/* Define to 1 if you have the `realpath' function. */
#undef HAVE_REALPATH
/* Define to 1 to include support for realtime clock. */
#undef HAVE_REALTIME
@@ -334,6 +394,9 @@
/* Define to 1 if you have the <stdarg.h> header file. */
#undef HAVE_STDARG_H
/* Define to 1 if stdbool.h conforms to C99. */
#undef HAVE_STDBOOL_H
/* Define to 1 if you have the <stddef.h> header file. */
#undef HAVE_STDDEF_H
@@ -361,6 +424,9 @@
/* Define to 1 if you have the `strerror' function. */
#undef HAVE_STRERROR
/* Define to 1 if you have the `strerror_r' function. */
#undef HAVE_STRERROR_R
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
@@ -370,6 +436,12 @@
/* Define to 1 if you have the `strncasecmp' function. */
#undef HAVE_STRNCASECMP
/* Define to 1 if you have the `strndup' function. */
#undef HAVE_STRNDUP
/* Define to 1 if you have the `strpbrk' function. */
#undef HAVE_STRPBRK
/* Define to 1 if you have the `strrchr' function. */
#undef HAVE_STRRCHR
@@ -385,7 +457,10 @@
/* Define to 1 if you have the `strtoul' function. */
#undef HAVE_STRTOUL
/* Define to 1 if `st_rdev' is a member of `struct stat'. */
/* Define to 1 if you have the `strtoull' function. */
#undef HAVE_STRTOULL
/* Define to 1 if `st_rdev' is member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_RDEV
/* Define to 1 if you have the <syslog.h> header file. */
@@ -489,6 +564,21 @@
/* Define to 1 if `vfork' works. */
#undef HAVE_WORKING_VFORK
/* Define to 1 if the system has the type `_Bool'. */
#undef HAVE__BOOL
/* Internalization package */
#undef INTL_PACKAGE
/* Locale-dependent data */
#undef LOCALEDIR
/* Define to 1 to include code that uses lvmlockd dlm option. */
#undef LOCKDDLM_SUPPORT
/* Define to 1 to include code that uses lvmlockd sanlock option. */
#undef LOCKDSANLOCK_SUPPORT
/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
slash. */
#undef LSTAT_FOLLOWS_SLASHED_SYMLINK
@@ -506,6 +596,12 @@
/* Define to 1 to include code that uses lvmetad. */
#undef LVMETAD_SUPPORT
/* Path to lvmlockd pidfile. */
#undef LVMLOCKD_PIDFILE
/* Define to 1 to include code that uses lvmlockd. */
#undef LVMLOCKD_SUPPORT
/* Path to lvmpolld pidfile. */
#undef LVMPOLLD_PIDFILE
@@ -544,9 +640,6 @@
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
@@ -588,6 +681,12 @@
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define to 1 if strerror_r returns char *. */
#undef STRERROR_R_CHAR_P
/* Path to testsuite data */
#undef TESTSUITE_DATA
/* The path to 'thin_check', if available. */
#undef THIN_CHECK_CMD

View File

@@ -25,11 +25,6 @@
#define _GNU_SOURCE
#define _FILE_OFFSET_BITS 64
/* Define some portable printing types */
#define PRIsize_t "zu"
#define PRIptrdiff_t "td"
#define PRIpid_t PRId32
#if defined(__GNUC__)
#define DM_EXPORTED_SYMBOL(func, ver) \
__asm__(".symver " #func "_v" #ver ", " #func "@@DM_" #ver )

View File

@@ -62,8 +62,11 @@ int exec_cmd(struct cmd_context *cmd, const char *const argv[],
*rstatus = -1;
if (sync_needed)
if (!sync_local_dev_names(cmd)) /* Flush ops and reset dm cookie */
return_0;
/* Flush ops and reset dm cookie */
if (!sync_local_dev_names(cmd)) {
log_error("Failed to sync local device names before forking.");
return 0;
}
log_verbose("Executing:%s", _verbose_args(argv, buf, sizeof(buf)));
@@ -148,8 +151,11 @@ FILE *pipe_open(struct cmd_context *cmd, const char *const argv[],
char buf[PATH_MAX * 2];
if (sync_needed)
if (!sync_local_dev_names(cmd)) /* Flush ops and reset dm cookie */
return_0;
/* Flush ops and reset dm cookie */
if (!sync_local_dev_names(cmd)) {
log_error("Failed to sync local device names before forking.");
return 0;
}
if (pipe(pipefd)) {
log_sys_error("pipe", "");

View File

@@ -33,7 +33,7 @@ static int _obtain_device_list_from_udev = DEFAULT_OBTAIN_DEVICE_LIST_FROM_UDEV;
static unsigned _external_device_info_source = DEV_EXT_NONE;
static int _trust_cache = 0; /* Don't scan when incomplete VGs encountered */
static int _debug_level = 0;
static int _debug_classes_logged = DEFAULT_LOGGED_DEBUG_CLASSES;
static int _debug_classes_logged = 0;
static int _log_cmd_name = 0;
static int _ignorelockingfailure = 0;
static int _security_level = SECURITY_LEVEL;
@@ -193,6 +193,11 @@ void set_cmd_name(const char *cmd)
_cmd_name[sizeof(_cmd_name) - 1] = '\0';
}
const char *get_cmd_name(void)
{
return _cmd_name;
}
void set_sysfs_dir_path(const char *path)
{
strncpy(_sysfs_dir_path, path, sizeof(_sysfs_dir_path) - 1);

View File

@@ -51,6 +51,7 @@ void init_detect_internal_vg_cache_corruption(int detect);
void init_retry_deactivation(int retry);
void set_cmd_name(const char *cmd_name);
const char *get_cmd_name(void);
void set_sysfs_dir_path(const char *path);
int test_mode(void);

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