1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-08-17 09:49:28 +03:00

Compare commits

...

489 Commits

Author SHA1 Message Date
731a9c1354 pre-release 2016-02-26 21:03:30 +00:00
9898126596 report: Shift (u)sed pv_attr under (a)llocatable.
Showing 'u' in the pv_attr reporting field is mostly unnecessary because
most PVs are allocatable, and being allocatable implies it is (u)sed,
and this is already obvious from other fields in the default 'pvs'
output like the VG name.

So move the new (u)sed pv_attr from character position 4 to 1, and only
show it in those rare cases when the PV is not (a)llocatable or the
relevant metadata is missing.

(Scripts should not be using pv_attr, but rather pv_allocatable,
pv_exported, pv_missing, pv_in_use etc.)
2016-02-26 15:46:37 +00:00
183bd8ca03 tests: skip on older version
Skip with older driver version.
Update address.
2016-02-26 10:21:36 +01:00
2988fa3c21 coverity: helping coverity with NULL pointer
Helping with understanding we will not try to deref NULL pointer,
as if the sizes are initialized to NULL it also means 'mem' would
be NULL, but thats too hard to model so make it obvious.
2016-02-26 10:21:36 +01:00
85a593c191 makefiles: add more dirs for lcov output
New daemons were missing in generated lcov output.
2016-02-26 10:21:34 +01:00
3e31f51869 dbus: fix the systemd service providing the DBus service
Correct name is lvm2-lvmdbusd.service not lvmdbusd.service.
This makes the bus-activation (auto-activation) work.

Signed-off-by: Vratislav Podzimek <vpodzime@redhat.com>
2016-02-26 10:20:08 +01:00
88530b2ef3 pvcreate: fix data alignment error check
Make the data_alignment variable 64 bits so it
can hold the invalid command line arg used in
pvreate-usage.sh pvcreate --dataalignment 1e.

On 32 bit arches, the smaller variable wouldn't
hold the invalid value so the error would not
trigger as expected by the test.
2016-02-25 17:02:18 -06:00
081359f6cd lvmdbusd: Do only 1 refresh for Vg.Change()
Signed-off-by: Tony Asleson <tasleson@redhat.com>
2016-02-25 16:43:56 -06:00
26b826ccf5 lvmdbusd testing: Add validatestate.py utility
This simple tool calls the Manager.Refresh method on the dbus service
to check and see if the dbus service has the most up to date state.
This is to be used for testing to ensure that event driven updates are
working as planned.

Signed-off-by: Tony Asleson <tasleson@redhat.com>
2016-02-25 16:43:55 -06:00
0d620e681f lvmdbustest.py: Move helper code to testlib.py
This will allow us to re-use in other client programs for testing.

Signed-off-by: Tony Asleson <tasleson@redhat.com>
2016-02-25 16:43:55 -06:00
f1bc68beb4 lvmdbusd: Reduce unnecessary state refreshes
When we use udev or have lvm call back into the dbus service when a
change occurs, even if that change originated from the dbus service
we end up refreshing the state of the system twice which is not
needed or wanted.  This change handles this case by removing any
pending refreshes in the worker queue if the state of the system
was just updated.

Signed-off-by: Tony Asleson <tasleson@redhat.com>
2016-02-25 16:43:55 -06:00
045d086a57 pvcreate: fix error from pv_write
After a pv_write() failure, the PV wasn't being skipped.
2016-02-25 16:40:24 -06:00
23a4801dbc tests: lvresize with zero arg 2016-02-25 23:30:26 +01:00
1a9f743eef cleanup: drop unneeded test
dmfree tests for NULL
2016-02-25 23:30:25 +01:00
e9b523e304 cleanup: indent
Last update missed to indent params.
2016-02-25 23:30:25 +01:00
5c29b54d4d cleanup: poll better check for internal errors 2016-02-25 23:30:25 +01:00
cdcf4cc794 lvconvert: use lp->repair
Set variable for repair testing.
2016-02-25 23:30:25 +01:00
ec8a75a321 lvconvert: use more display_lvname 2016-02-25 23:30:25 +01:00
86a651854f lvconvert: simplify handler processing
Easier code for handler init.
Drop release of pool mem - not needed, as command pool get dropped just
later.
2016-02-25 23:30:25 +01:00
abd9618dd8 lvconvert: fix vg parameter
Since we want to read env LVM_VG_NAME vg names,
we cannot just check LV names which do contain '/'.

So before the patch commands like:

> lvconvert --repair vg

Before:

Please provide a valid volume group name

After:
Path required for Logical Volume "vg".
Please provide a valid volume group name

> LVM_VG_NAME=vg lvconvert --repair vg

Before:
Please provide a valid volume group name

After:
Can't find LV vg in VG vg
2016-02-25 23:30:24 +01:00
a68e601886 lvresize: fix regression with zero size arg
Commit ca878a3426 introduced an issue
that zero sized extesion suddenly started to be accepted and
missed to return error.

Properly check invalid input values for sizes.
2016-02-25 23:29:57 +01:00
172bad0d56 Use a common message for a used PV
Change some inconsistent messages and adopt
the new wording "PV %s is used by" in place
of "PV %s is marked as belonging to"
or "PV %s belongs to".
2016-02-25 14:23:41 -06:00
66e175702a pvcreate: fix setting uuid arg
Commit 4de6caf5 ("redefine pvcreate structs") left
out setting the "idp" pointer to the "id" arg.
2016-02-25 12:00:53 -06:00
79f2596215 tests: add simple dmstats report tests
Add tests for the "dmstats report" command:

  * report
  * report --count
  * report --histogram

So far the tests just check the command runs as expected when a
correctly configured stats region exists: validation of output
can be added later.
2016-02-25 16:40:59 +00:00
3d3b132d9a tests: add dmstats create tests
Add tests for the "dmstats create" command:

  * simple whole-device region
  * region using --start/--len options
  * region using --segments option
  * region with precise timestamps (--precise)
  * region with histogram bounds (--bounds)
2016-02-25 16:40:59 +00:00
11fd7b7c64 tests: make lib/expected-version-dm a dependency of .tests-stamp 2016-02-25 16:40:59 +00:00
d4a5c252c5 tests: install does not depend on lib/version-expected
The install target already depends on .tests-stamp - since this
in turn depends on lib/version-expected there is no need to have
this as a dependency of install.
2016-02-25 16:40:59 +00:00
2d630ea78a tests: add template tests/shell/dmstats-create.sh
Add a template for testing 'dmstats create' operations.
2016-02-25 16:40:58 +00:00
3dae416229 tests: add driver_at_least() to aux.sh
Add a function to test whether the running device-mapper driver
version is at least equal to some given version.
2016-02-25 16:40:58 +00:00
1f8fd5a152 tests: add basic dmstats tests
Add initial dmstats tests to 000-basic.sh. These tests ensure that
the dmsetup binary is built and linked correctly when called as
'dmstats' and that the version of the binary matches the expected
library version used for the build.
2016-02-25 16:40:58 +00:00
985ed7822f dmstats: create dmstats symlink in test/lib
Create a symbolic link in test/lib for 'dmstats', pointing to the
dmsetup binary in the tools/ build directory.
2016-02-25 16:40:58 +00:00
42ae586fa7 lvmcache: fix missing free of vginfo->system_id causing mem leak 2016-02-25 16:25:27 +01:00
a77ded3001 replace pvcreate_params with pvcreate_each_params
"pvcreate_each_params" was a temporary name used
to transition from the old "pvcreate_params".

Remove the old pvcreate_params struct and rename the
new pvcreate_each_params struct to pvcreate_params.
Rename various pvcreate_each_params terms to simply
pvcreate_params.
2016-02-25 09:14:10 -06:00
4de6caf5b5 redefine pvcreate structs
New pv_create_args struct contains all the specific
parameters for creating a PV, independent of the
command.
2016-02-25 09:14:10 -06:00
c201ee09bd metadata: add fixme about code used only by liblvm 2016-02-25 09:14:10 -06:00
04d34da706 pvremove: use common toollib processing code
Use the new pvcreate_each_device() function from
toollib.
2016-02-25 09:14:09 -06:00
30c69b3f8a toollib: remove unsed pvcreate params function
which has been replaced by an equivalent pvcreate_each params
function.
2016-02-25 09:14:09 -06:00
0cd7d2332c liblvm: replace pvcreate_single with pvcreate_vol
And remove the pvcreate_single wrapper.
2016-02-25 09:14:09 -06:00
a9940bd3c9 vgcreate: use the common toollib pv create
Use the new pvcreate_each_device() function from
toollib, previously added for pvcreate, in place
of the old pvcreate_vol().

This also requires shifting the location where the
lock is acquired for the new VG name.  The lock for
the new VG is supposed to be acquired before pvcreate.
This means splitting the vg_lock_newname() out of
vg_create(), and calling vg_lock_newname() directly
before pvcreate, and then calling the remainder of
vg_create() after pvcreate.

The new function vg_lock_and_create() now does
vg_lock_newname() + vg_create(), like the previous
version of vg_create().

The lock on the new VG name is released before the
pvcreate and reacquired after the pvcreate because
pvcreate needs to reset lvmcache, which doesn't work
when locks are held.  An exception could likely be
made for the new VG name lock, which would allow
vgcreate to hold the new VG name lock across the
pvcreate step.
2016-02-25 09:14:09 -06:00
749a7cecf8 vgextend: use the common toollib pv create 2016-02-25 09:14:09 -06:00
6a1c22aadf pvcreate: use the common toollib pv create 2016-02-25 09:14:09 -06:00
71671778ab toollib: add two phase pv processing code
This is common code for handling PV create/remove
that can be shared by pvcreate/vgcreate/vgextend/pvremove.
This does not change any commands to use the new code.

- Pull out the hidden equivalent of process_each_pv
  into an actual top level process_each_pv.

- Pull the prompts to the top level, and do not
  run any prompts while locks are held.
  The orphan lock is reacquired after any prompts are
  done, and the devices being created are checked for
  any change made while the lock was not held.

Previously, pvcreate_vol() was the shared function for
creating a PV for pvcreate, vgcreate, vgextend.
Now, it will be toollib function pvcreate_each_device().

pvcreate_vol() was called effectively as a helper, from
within vgcreate and vgextend code paths.
pvcreate_each_device() will be called at the same level
as other process_each functions.

One of the main problems with pvcreate_vol() is that
it included a hidden equivalent of process_each_pv for
each device being created:

  pvcreate_vol() -> _pvcreate_check() ->

   find_pv_by_name() -> get_pvs() ->

     get_pvs_internal() -> _get_pvs() -> get_vgids() ->

       /* equivalent to process_each_pv */
       dm_list_iterate_items(vgids)
         vg = vg_read_internal()
         dm_list_iterate_items(&vg->pvs)

pvcreate_each_device() reorganizes the code so that
each-VG-each-PV loop is done once, and uses the standard
process_each_pv function at the top level of the function.
2016-02-25 09:14:09 -06:00
ff2267012a vgconvert: refactor to avoid pvcreate code
This uses the vg->pv_write_list in place of the
vg->pvs_to_write list, and eliminates the use of
pvcreate_params.  The label remove and zeroing
steps are shifted out of vg_write() to the higher
level like pvcreate will do.
2016-02-25 09:14:09 -06:00
5dd615c41e metadata: use pv_write_list for _check_old_pv_ext_for_vg
The _check_old_pv_ext_for_vg() function only needs to
do pv_write(), so it can use the simpler pv_list structs
on the pv_write_list.
2016-02-25 09:14:09 -06:00
bafbc72c8c metadata: refactor part of add_pv_to_vg
This shifts the use of the 'pv_to_write' struct
and the 'pvcreate_params' struct to the one
caller of add_pv_to_vg, which is made static.
2016-02-25 09:14:09 -06:00
5e5ad77f5f vg_write: add list of pvs to write
The vg->pv_write_list contains pv_list structs for which
vg_write() should call pv_write().

The new list will replace vg->pvs_to_write that contains
vg_to_create structs which are used to perform higher-level
pvcreate-related operations. The higher level pvcreate
operations will be moved out of vg_write() to higher levels.
2016-02-25 09:14:09 -06:00
3ac860334b configure 2016-02-25 13:58:48 +00:00
718a695b0c configure: require sanlock 3.3.0
For a sanlock flag added in that version.
2016-02-24 13:22:23 -06:00
664fa6d1be lvmlockd: use new sanlock flag to avoid blocking
This flag allows sanlock requests to avoid all blocking.
2016-02-24 10:10:59 -06:00
77f034bfa3 tests: include lvmlockd in default make check 2016-02-23 16:34:46 -06:00
e793253084 lvmlockd: fix sparse snapshot case
A snapshot can be created without a real origin LV
in this case, so there's no lock to use.
2016-02-23 15:45:25 -06:00
79809d6cdc cleanup: use sizeof instead of macro.
Keep the buffer size defined at a single place and then use
its sizeof.
2016-02-23 21:40:17 +01:00
9267e0c5e7 cleanup: use braces around macro params 2016-02-23 21:40:17 +01:00
63c052b9e2 coverity: ensure thin_pool_seg is not NULL
thin_pool_seg being NULL would be an internal error.
2016-02-23 21:40:17 +01:00
ddfec5b51a coverity: use same arithmetic for both major and minor
Run all arithmetic in the same 'dev_t' type.
2016-02-23 21:40:17 +01:00
9e3a9eab0e coverity: check for dm_snprintf
Check return state like everywhere else.
2016-02-23 21:40:17 +01:00
a9634e993a coverity: check cmd pointer exists
Since in _report_init() we check few times for cmd != NULL
keep it consistent and Coverity happier.
2016-02-23 21:40:16 +01:00
68955a8102 coverity: ensure non-null pointers are used
Here is too complex for Coverity to guess
those pointers cannot be NULL, but it's
very easy to add little checks here.
2016-02-23 21:40:16 +01:00
9b92cb2760 coverity: drop unused assignments 2016-02-23 21:40:16 +01:00
eaaae185b7 coverity: check for zero length buffer
When get_shared_library_path() would got zero length buffer,
it could have underflow in size calc later.
So just put extra small check for this case.
2016-02-23 21:40:16 +01:00
b08eb91df1 coverity: check for info pointer existance
Since we already check in few other places  'info' is not NULL,
do the same for others - however when info would be NULL
it more or less looks like internal error.
2016-02-23 21:40:16 +01:00
2e168a52b0 coverity: drop unneeded header 2016-02-23 21:40:12 +01:00
6d6e063a0f libdm: fix string boundary
The test for string 'end' needs to account for ending \0,
which also needs to fit <SIZE.
2016-02-23 21:38:52 +01:00
eccc91f9b0 lvmlockd: set default result value
The default error value should be set indicating
an error.
2016-02-23 14:35:40 -06:00
0236a34224 tests: updates for check_lvmlockd
Move the lvmlockd-related setup functions into aux.

For check_lvmlockd_test, start a new instance of
lvmlockd --test for each shell test.
2016-02-23 14:00:28 -06:00
42da7a6c38 make: Add check_lvmlockd_* targets to top-level 2016-02-23 18:34:46 +01:00
f54253d396 tests: add SKIP_WITH_LVMLOCKD
to all tests that don't already used vgcreate $SHARED
2016-02-23 09:28:48 -06:00
5d7e83c73c tests: check warn about belong is printed 2016-02-23 14:41:24 +01:00
c0b836e316 gcc: logical-op warning go away
Don't be too much inventive and shutdown gcc6 warning:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69602
2016-02-23 14:41:24 +01:00
05cc1b87a9 gcc: cleanup Wunused-const-variable
Use #define instead, since we do not require actually buffer needs
to exists to eliminated new gcc6 warning:

clvm.h:53:19: warning: ‘CLVMD_SOCKNAME’ defined but not used
[-Wunused-const-variable]
2016-02-23 14:41:24 +01:00
e717ce555b pvremove: add warn when removing PV in use
Reshuffle messages during pvremove.

Always print WARNING: when PV is in use so using options
--force --force doesn't make this important user
notification go away.

Simplify variable 'used' usage (so older gcc doesn't warn
about the use of unitilizied variable).

Add some '.' into messages.
2016-02-23 14:40:30 +01:00
7d8a67714f cleanup: drop double ; 2016-02-23 12:25:25 +01:00
dbc71dc05e gcc: cleanup some sign warnings
When comparing unsigned with int, the comparision is made
as 'unsigned' type, so make it rather explicit which type
is being compared.
2016-02-23 12:25:25 +01:00
293aabe4cd cache: enforce header check
Currently it's been checked for 'zero' header for thin-pool,
but lets use it always for cache as well - since it's relatively 'cheap'
detection of read 'error' problems as thin/cache tools
currently do not work fast enough in this case.
2016-02-23 12:25:25 +01:00
f501f083bf thin: fix read size compare
Fix the compare with 'unsigned' sizeof() and error read -1 result.
So the read error is correctly recognized.
2016-02-23 12:22:18 +01:00
05eb87ca2d lvmdbusd: Initial unit test driver script
It's disabled until we can fix it up.

Signed-off-by: Tony Asleson <tasleson@redhat.com>
2016-02-22 16:07:54 -06:00
ecc0406886 lvmdbusd: Remove unlimited retries
Change while to for loop to prevent the daemon from getting stuck
when lvm is messed up.

Signed-off-by: Tony Asleson <tasleson@redhat.com>
2016-02-22 16:07:54 -06:00
21034644b6 lvmdbusd: Add env variable to use session bus
export LVMDBUSD_SESSION=True to run on the session bus instead
of the system bus so that we can run the unit test without
installing the dbus conf file.

Signed-off-by: Tony Asleson <tasleson@redhat.com>
2016-02-22 16:07:54 -06:00
64aab5885d lvmdbus: Make unit tests work in test env
Reduced the size of LVs created and use actual PE numbers instead of hard
coding them to allow us to work with the loop back devices.

Signed-off-by: Tony Asleson <tasleson@redhat.com>
2016-02-22 16:07:54 -06:00
70d0b210e1 lvmdbusd: background.py, fix stdout parse error
It appears that the output of lvconvert --merge can vary some.  The code
was blowing up as it was trying to parse a line of stdout to retrieve the
% complete, but the line did not have the needed format and an execption
was thrown.  The uncaught exception caused the background thread to exit
without updating the job object, which caused the client to hang forever
waiting.  Added a default exception handler to prevent unhandled execptions
causing hangs and removed the parameter skip_first_line as it's no longer
needed.  The code checks to see if the line can be parsed before doing so.

Signed-off-by: Tony Asleson <tasleson@redhat.com>
2016-02-22 16:07:54 -06:00
d7dd8bf9d6 lvmdbustest.py: Make executable
Signed-off-by: Tony Asleson <tasleson@redhat.com>
2016-02-22 16:07:54 -06:00
f4efc2435c tests: fix clean up after lvmlockd tests 2016-02-22 14:15:17 -06:00
ec81c42179 lvmdbusd: Fix make install for python >= 3.5
python 3.5 renamed .pyo files to .opt-1.pyc.
2016-02-22 18:16:41 +01:00
367fb85e44 spec: Fix 04ab1fa572: Remove left-overs 2016-02-22 17:50:35 +01:00
c716813651 lvmlockd: invalidate name in lockspace struct after remove
After the lockspace has been successfully removed,
invalidate the name field in the lockspace struct.
The struct remains on the list of lockspaces until
the struct can be freed later.  Until the struct is
freed, its name will prevent another new lockspace
from being created with the same name.
2016-02-22 09:36:35 -06:00
161ae36363 test: add make check_lvmlockd_test
Which runs lvmlockd in --test mode, without
any lock manager.

Also make some adjustments to the check_lvmlockd
variations using the lock managds.
2016-02-22 09:36:35 -06:00
ed5e5c38b5 tests: skip thin-flags test on 32bit el6 kernel
Until kernel is fixed, stop running test always hitting OOPS there.
2016-02-22 14:59:28 +01:00
3178cfc818 cleanup: use char arrays. 2016-02-22 14:27:44 +01:00
2d6ef123a6 cleanup: indent changes
Some code indention.
Use dm_strncpy() for simplier code.

TODO: we could possibly use   %32s  for printing pvid...
so maybe adding extra  FMT_PVID....
2016-02-22 14:26:15 +01:00
fba54ae55e cleanup: libdm clang warnings
Add some extra clang pointer validation so we do not try deref NULL.
2016-02-22 14:18:28 +01:00
275c9f7e77 libdm: grow with initialized struct content
Coverity noticed struct hist has been copied uninitalized into mempool.
2016-02-22 14:17:32 +01:00
30a73d1604 lvmetad: fix error path
Coverity noticed the internal error path would  be using uninit struct.
So always make sure reply is initilized.
2016-02-22 14:15:53 +01:00
44b3909e58 post-release 2016-02-21 23:37:48 +00:00
3ef36f05b6 pre-release 2016-02-21 23:17:24 +00:00
8b6cad3219 lvmdbustest.py: resync latest changes
This file update was missed, copied latest file from:
https://github.com/tasleson/lvm-dubstep/blob/master/test/lvmdbustest.py

Signed-off-by: Tony Asleson <tasleson@redhat.com>
2016-02-19 15:16:05 -06:00
eefcbd5b28 thin: fix update_pool_lv error path
When update fails in suspend() (sending of messages
fails because metadata space is full) call resume(),
so the locking sequence works properly for clustering.

Also failing deactivation should unlock memory.
2016-02-19 11:25:56 +01:00
04ab1fa572 spec: Update python bindings and dbus-service
The workaround for python3 is no longer needed.
2016-02-18 20:46:03 +01:00
a89ddda1a2 tests: needs_check needs version 16
Skip part of test when driver is too old.
2016-02-18 18:11:29 +01:00
42b394c142 thin: fix test for nonexisting status
Check status has right type.
2016-02-18 18:11:29 +01:00
bcf7f80791 tests: checking thin flags
Test various  (D/M/F) attrs for thin-pool/thin
2016-02-18 16:49:38 +01:00
485bce1ae3 man: lvs updates 2016-02-18 16:49:38 +01:00
f31d596c0d thin: report needs_check and fail state
Fix reporting of Fail thin-pool target status
as attr[8] letter 'F'.

Report  'needs_check' status from thin-pool target via
attr field [4] (letter 'c'/'C'), and also via CheckNeeded field.

TODO: think about better name here?
TODO: lots of prop_not_implemented_set
2016-02-18 16:49:34 +01:00
0358ca3aad thin: report PERCENT_INVALID for failed pool
When thin-pool is in failed/error state, we can't
read percentage so report invalid value.
2016-02-18 16:45:42 +01:00
0fb3669d49 libdm: thin status update
Fix parsing of 'Fail' status (using capital letter) for thin-pool.
Add also parsing of 'Error' state for thin-pool.
Add needs_check test for thin-pool.

Detect Fail state for thin.
2016-02-18 16:45:42 +01:00
ecfa465366 metadata: ask for confirmation before really initializing/removing PV that is marked as belonging to a VG
Ask for confirmation when using pvcreate/pvremove on a PV which is
marked as belonging to a VG, just like we do in case of a PV which
belongs to known VG:

$ pvcreate -ff /dev/sda
Really INITIALIZE physical volume "/dev/sda" that is marked as belonging to a VG [y/n]? n
  /dev/sda: physical volume not initialized

$ pvremove -ff /dev/sda
Really WIPE LABELS from physical volume "/dev/sda" that is marked as belonging to a VG [y/n]? n
  /dev/sda: physical volume label not removed
2016-02-18 14:33:54 +01:00
1a141e8623 lbmdbusd: Support in-tree testing. 2016-02-18 13:26:08 +00:00
ef5583a209 Fix rpm builds 2016-02-18 12:37:44 +01:00
bc19a16fc7 report: report -1, not 'unkown' for lv_{snapshot_invalid,merge_failed} with --binary
State:
$ lvs -o lv_name,lv_active_locally,lv_snapshot_invalid,lv_merge_failed vg/lvol0
  LV    ActLocal       SnapInvalid     MergeFailed
  lvol0 active locally         unknown         unknown

Now with using --binary switch.

Before this patch (lv_snapshot_invalid and lv_merge_failed not switched into numeric value
where -1 represents 'unknown' value)
$ lvs -o lv_name,lv_active_locally,lv_snapshot_invalid,lv_merge_failed vg/lvol0 --binary
  LV    ActLocal   SnapInvalid     MergeFailed
  lvol0          1         unknown         unknown

With this patch applied:
$ lvs -o lv_name,lv_active_locally,lv_snapshot_invalid,lv_merge_failed vg/lvol0 --binary
  LV    ActLocal   SnapInvalid     MergeFailed
  lvol0          1              -1              -1
2016-02-18 12:10:00 +01:00
e5fc48411a configure: Use python-config if python2-config not found.
Assume that's good enough for older systems.
2016-02-18 02:10:35 +00:00
7dce72ee18 . 2016-02-18 01:50:36 +00:00
6af2ce6244 lvmdbusd: Rename module to lvmdbusd 2016-02-18 01:14:56 +00:00
887e96ded7 autoconf: Fix py-compile permissions 2016-02-18 01:05:05 +00:00
0f353e2053 lvmdbus: resync latest changes with original repo 2016-02-18 00:27:57 +00:00
545e58fd18 WHATS_NEW 2016-02-18 00:01:02 +00:00
5987562cf9 lvmdbus: Add new daemon. 2016-02-17 23:53:35 +00:00
055c628e38 man: fix list of restricted LV name suffixes 2016-02-17 15:38:27 +01:00
065526c590 metadata: add missing _repair_inconsinstent_vg call during PV ext repair 2016-02-17 10:19:55 +01:00
b077e7374f metadata: do not repair missing PV_EXT_USED flag for PVs belonging to foreign VG
The host that owns foreign VGs is responsible for fixing up PV_EXT_USED
flag - the same already applies to repairing any inconsistent VG.

This patch also moves the iteration over vg->pvs inside
_check_or_repair_pv_ext fn - it's cleaner this way.
2016-02-17 10:19:24 +01:00
13f3e92632 refactor: add common _is_foreign_vg fn 2016-02-16 13:44:48 +01:00
45be3c875f pv: use pv->fmt to check for fake PVs, not pv->vg
pv->vg is not set yet during pvcreate processing. Use pv->fmt instead to
check for these fake PVs (all normal PVs have format defined, devices
which are not PVs don't have this set).

This fixes commit 0000db7f98.
2016-02-15 15:52:13 +01:00
099d99975c cleanup: make the message about marked PVs consistent with the others 2016-02-15 15:20:23 +01:00
cc9e683adc toollib: skip PV if system ID is used and PV marked as used but metadata missing
If we know that a PV belongs to some VG and we're missing metadata
(because we have only those PV(s) from VG present in the system that
don't have metadata areas), we should skip such PV when processing
under system ID.

This is because we know that the PV belongs to some VG, but we
really can't decide whether it matches system ID unless the VG
metadata is present again.
2016-02-15 15:17:36 +01:00
0000db7f98 pv: mark fake PVs as not used
Some of the PVs are not even orphan PVs - they're fake PVs - this can
happen if we're listing all devices with "pvs -a". Such PV must not
be marked as used.
2016-02-15 14:46:31 +01:00
abbaeef096 cleanup: use is_used_pv fn to detect whether PV is in use while reporting pv_free field 2016-02-15 13:30:37 +01:00
698e0eb851 WHATS_NEW: PV_EXT_USED flag and related 2016-02-15 13:07:35 +01:00
8ad93874d6 tests: fix tests checking pv_attr - there's a new bit now 2016-02-15 12:44:46 +01:00
a4e25f4381 tests: add pv-ext-flags.sh test
Testing PV extension flags. Currently, there's only one PV extension
flag present - the PV_EXT_USED flag (marking PV as used in a VG).
2016-02-15 12:44:46 +01:00
2f00d57e6f vg: automatically update to newest PV ext version during vg_write 2016-02-15 12:44:46 +01:00
9b9f1ae772 format: format_text: add pv_needs_rewrite to format_handler and implemention for format_text 2016-02-15 12:44:46 +01:00
08de88535e report: identify used PVs in pv_attr field with 'u' char 2016-02-15 12:44:46 +01:00
db494d7d34 report: always display 0 for pv_free field if we don't have any mda and PV is marked as used at the same time 2016-02-15 12:44:46 +01:00
d84a80afb5 backup: backup_restore_vg: register PVs that need writing via vg->pvs_to_write list
The backup_restore_vg is used directly for restoring the VG from backup.
It's also used to do the VG conversions from one metadata format to
another which means vgconvert calls backup_restore_vg too.

When restoring VG from backup, we need to rewrite/write PV headers as
PVs may have been orphans before and now they're becoming part of some
VG - we need to write the PV_EXT_USED flag at least.

When using the backup_restore_vg for vgconvert, we need to write
completely new PV header in different format.

Avoid the special "pv_write" call and handling that was used before
this patch in vgconvert (vgconvert_single function to be more precise)
and reuse existing internal interface to register PV header for writing
(or rewriting) via vg->pvs_to_write list instead like we do it elsewhere
in the code.

This patch also resolves a problem in which PV headers with target
format were written in the vgconvert_single fn as orphans and VG
metadata were added later on - this was a tiny hack actually.
We can't do this now - we need to write the PV as belonging
to a VG because otherwise the PV_EXT_USED flag won't be written
properly (if the PV header is written as orphan, the PV_EXT_USED
is set to 0, of course, even though metadata are attached later).
So this patch removes this tiny inconsistency which was passing
just fine before because we didn't have any relation to the VG
in PV header before. Now we have the PV_EXT_USED flag which says
the "PV is used in some VG".
2016-02-15 12:44:46 +01:00
531ced90dc metadata: _vg_read: check if PV_EXT_USED flag is set correctly for non-orphan PVs and do a repair if needed
The same check as we already do for orphan PVs, just the other way
round now: if the PV is surely part of some VG and any PV the VG
contains does not have the PV_EXT_USED flag set, repair it.

For example - /dev/sda here is in VG vg and it's incorrectly not
marked as used by PV_EXT_USED flag:

pvs --binary -o pv_ext_vsn,pv_in_use
  WARNING: Volume Group vg is not consistent.
  WARNING: Repairing Physical Volume /dev/sda that is in Volume Group vg but not marked as used.
  PV         VG     Fmt  Attr PSize   PFree   ExtVsn PInUse
  /dev/sda   vg     lvm2 a--  124.00m 124.00m      2      1
2016-02-15 12:44:46 +01:00
f75e42c06c report: add pv_ext_vsn field to display PV header extension version used
For example:

$ pvs -o pv_name,vg_name,pv_ext_vsn,pv_in_use
  PV         VG     ExtVsn InUse
  /dev/sda               2
  /dev/sdb   vg          2    used
  /dev/vda2  fedora      1    used
2016-02-15 12:44:46 +01:00
e0b1415105 metadata: check for PV extension version before doing any checks on PV extension flags
PV header extension versions:
  0 - the original PV without any extensions
  1 - bootloader area support added
  2 - PV_EXT_USED flag support added

So do the associated checks related to PV_EXT_USED flag only if
PV header extension found is of version 2 and higher.
2016-02-15 12:44:46 +01:00
d97f1c89de metadata: _vg_read: check if PV_EXT_USED flag is set correctly for orphan PVs and do a repair if needed
If we know that the PV is orphan, meaning there's at least one MDA on
that PV which does not reference any VG and at the same time there's
PV_EXT_USED flag set, we're certainly in an inconsistent state and we
need to fix this.

For example, such situation can happen during vgremove/vgreduce if we
removed/reduced the VG, but we haven't written PV headers yet because
vgremove stopped abruptly for whatever reason just before writing new
PV headers with updated state, including PV extension flags (and so the
PV_EXT_USED flag).

However, in case the PV has no MDAs at all, we can't double-check
whether the PV_EXT_USED is correct or not - if that PV is marked
as used, it's either:
  - really used (but other disks with MDAs are missing)
  - or the error state as described above is hit

User needs to overwrite the PV header directly if it's really clear
the PV having no MDAs does not belong to any VG and at the same time
it's still marked as being in use (pvcreate -ff <dev_name> will fix this).

For example - /dev/sda here has 1 MDA, orphan and is incorrectly marked
with PV_EXT_USED flag:

$ pvs --binary -o+pv_in_use
  WARNING: Found inconsistent standalone Physical Volumes.
  WARNING: Repairing flag incorrectly marking Physical Volume /dev/sda as used.
  PV         VG     Fmt  Attr PSize   PFree   InUse
  /dev/sda          lvm2 ---  128.00m 128.00m     0
2016-02-15 12:44:46 +01:00
3436d5b791 report: add pv_in_use field to display whether PV is in use or not
For example:

$ pvs -o pv_name,vg_name,pv_in_use
  PV         VG     InUse
  /dev/sda   vg      used
  /dev/sdb
  /dev/sdc           used

(sda is part of vg - it's used
 sdb is not part of vg - it's not used
 sdc is part of vg, but MDAs missing - it's used)
2016-02-15 12:44:46 +01:00
b6e3080fff pv: _pvcreate_write: do label removal and zeroing only if creating a new PV 2016-02-15 12:44:46 +01:00
73f1d444c8 pv: issue different message of different type when we're overwriting existing PV header instead of creating a new one
Scenario:

$ pvcreate /dev/sda
  Physical volume "/dev/sda" successfully created

We're adding the PV to a VG.

Before this patch:
$ vgcreate vg /dev/sda
  Physical volume "/dev/sda" successfully created
  Volume group "vg" successfully created

With this path applied:
$ vgcreate vg /dev/sda
  Volume group "vg" successfully created

...and verbose log containing: "Physical volume "/dev/sda" successfully written"
2016-02-15 12:44:46 +01:00
52999133a3 pv: check for the PV_EXT_USED flag and deny pvcreate/pvchange/pvremove/vgcreate on such PV (unless forced)
Make sure we won't use a PV that is already marked as used. Normally,
VG metadata would stop us from doing that, but we can run into a
situation where such metadata is missing because PVs with MDAs
are missing and the PVs left are the ones with 0 MDAs.

(/dev/sda in this example has 0 MDAs and it belongs to a VG,
but other PVs with MDA are missing)

$ pvs -o pv_name,pv_mda_count /dev/sda
  PV         #PMda
  /dev/sda       0

$ pvcreate /dev/sda
  PV '/dev/sda' is marked as belonging to a VG but its metadata is missing.
  Can't initialize PV '/dev/sda' without -ff.

$ pvchange -u /dev/sda
  PV '/dev/sda' is marked as belonging to a VG but its metadata is missing.
  Can't change PV '/dev/sda' without -ff.
  Physical volume /dev/sda not changed
  0 physical volumes changed / 1 physical volume not changed

$ pvremove /dev/sda
  PV '/dev/sda' is marked as belonging to a VG but its metadata is missing.
  (If you are certain you need pvremove, then confirm by using --force twice.)

$ vgcreate vg /dev/sda
  Physical volume '/dev/sda' is marked as belonging to a VG but its metadata is missing.
  Unable to add physical volume '/dev/sda' to volume group 'vg'.
2016-02-15 12:44:46 +01:00
d320d9c52b pv: format-text: store PV_EXT_USED flag if PV is used and unset it otherwise
When adding a PV to VG, set the PV_EXT_USED flag in PV header and
vice versa - if the PV is no longer in a VG, unset the flag.
2016-02-15 12:44:46 +01:00
10128c9bd6 metadata: schedule PV for header rewrite if adding a PV to VG or restoring VG
When adding PV to VG, we need to rewrite PV header as there's a flip
in PV_EXT_USED flag. The same applies if we're restoring VG from backup.
2016-02-15 12:44:46 +01:00
2950adc2ab metadata: add_pv_to_vg: add 'new_pv' arg to state if the PV is about to be created 2016-02-15 12:44:46 +01:00
4cbaaa5c98 pv: add is_used_pv fn 2016-02-15 12:44:46 +01:00
71ea2e1602 lvmcache/lvmetad: cache PV extension version
Store PV extension version in lvmcache/lvmetad for use throughout the code.
2016-02-15 12:44:46 +01:00
7593221f94 lvmcache/lvmetad: cache PV extension flags
Store PV extension flags in lvmcache/lvmetad for use throughout the code.
2016-02-15 12:44:46 +01:00
54b41db9a6 metadata: introduce PV_EXT_USED flag and bump PV_HEADER_EXTENSION_VSN 2016-02-15 12:44:46 +01:00
a522af93b7 format: add FMT_PV_FLAGS to indicate format supports PV flags 2016-02-15 12:44:46 +01:00
4361543f3e refactor: rename struct pv_to_create --> struct pv_to_write
We'll use this struct in subsequent patches for PVs which should
be rewritten, not just created. So rename struct pv_to_create to
struct pv_to_write for clarity.
2016-02-15 12:44:45 +01:00
952498ef4d post-release 2016-02-15 10:48:55 +00:00
228b8245e4 pre-release 2016-02-15 10:35:16 +00:00
672deaebc5 man: pvresize: remove old comment about inability to resize PV with more mdas 2016-02-12 16:29:47 +01:00
337aa4ca8e tests: indent
Better bash indention
2016-02-12 11:59:42 +01:00
0daf9d7ac5 pvmove: fix possible memory pool corruption
This is a hotfix for a bug introduced in
6d7dc87cb3.

The bug description: First we allocate memory for
processing handle (at an address 1) then we
allocate some memory on the same pool for later use
in pvmove_poll function inside the process_each_pv
function (at an address 2). After we jump out of
process_each_pv we called destroy_processing_handle.
As a result of destroying the handle memory pool could
deallocate all memory at address 1 or higher. The
pvmove_poll function tried to copy a memory allocated
at address 2 that could be returned to the system.
If it was so it led to segfault.

We need to rethink proper fix but in the same time
cmd->mem pool is recreated per each lvm command so
this should not cause problems even when we run
multiple commands in lvm shell.

A valgrind snapshot of the corruption:

Invalid read of size 1
    at 0x4C29F92: strlen (mc_replace_strmem.c:403)
    by 0x5495F2E: dm_pool_strdup (pool.c:51)
    by 0x1592A7: _create_id (pvmove.c:774)
    by 0x159409: pvmove_poll (pvmove.c:796)
    by 0x1599E3: pvmove (pvmove.c:931)
    by 0x15105B: lvm_run_command (lvmcmdline.c:1655)
    by 0x1523C3: lvm2_main (lvmcmdline.c:2121)
    by 0x1754F3: main (lvm.c:22)
Address 0xf15df8a is 138 bytes inside a block of size 8,192 free'd
    at 0x4C28430: free (vg_replace_malloc.c:446)
    by 0x5494E73: dm_free_wrapper (dbg_malloc.c:357)
    by 0x5495DE2: _free_chunk (pool-fast.c:318)
    by 0x549561C: dm_pool_free (pool-fast.c:151)
    by 0x164451: destroy_processing_handle (toollib.c:1837)
    by 0x1598C1: pvmove (pvmove.c:903)
    by 0x15105B: lvm_run_command (lvmcmdline.c:1655)
    by 0x1523C3: lvm2_main (lvmcmdline.c:2121)
    by 0x1754F3: main (lvm.c:22)
2016-02-12 11:40:33 +01:00
a077a64983 tests: update test
Upgrade test to count with much faster dmeventd work thanks
to low_watter_mark support.

Fix some wrong tests.
2016-02-12 10:21:07 +01:00
befe0078ad gcc: better code for older compiler
Address this gcc warning:

metadata/lv.c:243: warning: initialized field overwritten
metadata/lv.c:243: warning: (near initialization for 'status.seg_status')

Present with e.g.: gcc version 4.3.2 (Debian 4.3.2-1.1)
2016-02-12 10:17:39 +01:00
ba111e7f4a tests: check for automated dmeventd resize
Watermark support should handle relatively quickly data LV resizes.
So check if it does what is expected.
2016-02-11 18:38:40 +01:00
53058e5234 debug: cut_and_paste type in message
Typo in debug message.
2016-02-11 18:38:40 +01:00
cc23fdbd13 cleanup: update messages 2016-02-11 18:38:40 +01:00
5a32d2c1d9 cleanup: drop unneeded assigns 2016-02-11 18:35:07 +01:00
032cf8ade6 cleanup: relocate function to vg.c 2016-02-11 18:35:06 +01:00
acf7815aca cleanup: stripes_extents
Simplify calculation of extents rounding needed for
segment size.

Segment size has to divisible by 'extent count' needed to contain
whole stripe. LVM currently does not support stripes across segment.

In case the stripe size is bigger then extent size,
require bigger rounding.
2016-02-11 18:35:06 +01:00
740d27f9fe cleanup: rename usepolicies
Switch to ARG name without '_' in the middle (like all others args).
2016-02-11 18:35:06 +01:00
3f916e8285 lvresize: check for given parameters
Check ac_ value as passed args.
Also drop reseting 'computed' values - since they get
assigned values later.
2016-02-11 18:35:06 +01:00
0baf66a992 dm: alloc always 8byte aligned
Fixing regression caused by 197b5e6dc7.
So the 'TODO' part now finally know the answer - there is 'sparc64'
architecture which imposes limitation to read 64b words only through
64b aligned address.

Since we never could know how is the user going to use the returned
pointer and the userusually expects it's aligned on the highest CPU
required alignement, preserve it also for char*.

Fixes: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=809685
Reported-by: Anatoly Pugachev <matorola@gmail.com>
2016-02-11 18:35:05 +01:00
f91622741f dm: fix thin-pool targer params order
Wrong thin-pool feature flag ordering in dm table: It will lead to
unnecessary table reload.

Fix it by placeing feature flags in order they are returned from the
kernel so current 'table line diff' code will not see a difference.
2016-02-11 18:32:24 +01:00
e32e793c43 lvconvert: enable spare creation during conversion
Let user control pool metadata spare creation after repair as
the VG might not have enough free space.
2016-02-11 18:30:40 +01:00
3b76e9fd98 config: fix verbose type to int
'verbose' was marked as a boolean option while it
takes integer args - so it has limited usage to 0 or 1,
but we supported 0-4 at least.

Fix it by switching to corrent int type.
(Hopefully noone was trying to use this variable as true/yes/false/no
way - as the would be unsupported/undocumented).
2016-02-11 18:30:39 +01:00
02f2916b5b thin: fix low_water_mark threshold calc
Reporter noticed lvm2 incorrectly translated
lvm2 threshold value to  water mark in commit:
99237f0908

Fix it by properly translating size to number of
blocks in thin-pool and then calc for free blocks
matching configured lvm2 threshold value.

Reported-by: Ming-Hung Tsai <mingnus@gmail.com>
2016-02-11 18:30:24 +01:00
8423be80ee conf: use use_blkid_wiping=0 if not defined in lvm.conf and support not compiled in
Normally, we generate and provide lvm.conf file where use_blkid_wiping
is set based on whether support for this is compiled in or not. This was
generated properly based on configure.

However, if lvm.conf is not used at all (someone deletes it) or the value
in lvm.conf is commented out (user edited it), we still need to use
proper default value that is based on DEFAULT_USE_BLKID_WIPING taken
from configure script - we used hardcoded value of "1" in this case
by mistake.
2016-02-10 14:53:10 +01:00
c0e0f5a923 filter: do not check for suspended devs in filter-usable in lvmetad mode
We already do check for suspended devs within udev rules where
the pvscan is to update lvmetad. So the check for suspended devs
in "pre-lvmetad" chain is not useful here - remove it - it may
be a source of hardly to detect races anyway (if udev rule detects
the device is not suspended and then the pvscan instance sees the
dev as suspended, we may end up not reacting to the event properly).
2016-02-03 14:57:36 +01:00
1498bc8cc4 metadata: format: also delete bootloader areas from lvmcache when reading lvm1 and pool label
lvm1 and pool format do not support bootloader areas and we need to
remove any existing associated bootloader areas when we read lvm1 and
pool labels.

This has its importance if we're converting from one format to another
and we're reusing lvmcache in long-running commands (e.g. clvmd or lvm
shell) and we need to make lvmcache consistent and valid for current format.
2016-02-02 13:57:19 +01:00
ec43f55445 filters: partitioned: fix partition table filter with external_device_info_source="udev" and blkid<2.20
Non-dm devices have ID_PART_TABLE_TYPE variable exported in
udev db from blkid scan for *both* whole devices and partitions.
We used ID_PART_ENTRY_DISK in addition to decide whether this
is the whole device or partition and then we filtered out only
whole devices where the partition table really is.

However, ID_PART_ENTRY_DISK was added in blkid 2.20 so we need
to use a different set of variables to decide on whole devices
and partitions on systems where older blkid is still used.

Now, we use ID_PART_TABLE_TYPE to detect that there's something
related to partitioning with this device and we use DEVTYPE variable
instead to decide between whole device (DEVTYPE="disk") and partition
(DEVTYPE="partition").

For dm devices it's simpler, we have ID_PART_TABLE_TYPE variable\
set in udev db for whole devices. It's not set for partitions,
hence we don't need more variable in addition to make the decision
on whole device vs. partition (dm devices do not have regular
partitions, hence DEVTYPE can't be used anyway, it's always set
to "disk" for whole disks and partitions).
2016-02-02 13:28:11 +01:00
762b0d697f lvmlockd: don't adopt locks from unused lm
When built without dlm or sanlock support, don't
attempt to adopt locks from that lm.
2016-01-28 09:42:45 -06:00
0ad40a76c0 post-release 2016-01-25 01:12:27 +00:00
d05d7d974c pre-release 2016-01-25 01:08:16 +00:00
bc8f8ac0fa tests: add pv-check-dev-size.sh 2016-01-22 14:16:00 +01:00
136fd8f2f6 conf: add metadata/check_pv_device_sizes 2016-01-22 14:16:00 +01:00
c0912af310 metadata: check PV dev size is not less than PV size 2016-01-22 14:16:00 +01:00
1f5dfb7369 lvmcache: invalidate all cached dev sizes if all VGs got unlocked 2016-01-22 14:16:00 +01:00
d090d6574e device: also cache device size
Add "size" and "size_seqno" to struct device to cache device's size
and also to control its lifetime - the cached value is valid as long
as the global _dev_size_seqno is equal to the device's size_seqno,
otherwise we need to get the size again and cache the new value.

This patch also adds new dev_size_seqno_inc() fn for the appropriate
parts of the code to increment current global value of _dev_size_seqno
and hence to cause all currently cached values for device sizes to
be invalidated.

The device size is now cached because we're planning to reuse this
information for further checks and we want to avoid checking it more
than necessary to save resources.
2016-01-22 14:13:34 +01:00
dc388e0c7a lvmlockd: remove noisy log_debug
The debug message appeared even when lvmlockd was not used,
and the lockd operation was simply being skipped.
2016-01-21 14:37:15 -06:00
55056c2d16 vgimportclone: fix VG name variable reference in error message after failed PV uuid change 2016-01-21 14:47:48 +01:00
22810155a6 cleanup: add missing prototype
Commit 2304286f68
missed to add function prototype.
2016-01-21 13:29:08 +01:00
347575df1d toollib: restore command break support
Fix regression caused by c9f021de0b.
This commit actually transfered real-action (e.g. device removal)
into the next loop which has however missed to check for break.
So add check for break also there.
2016-01-21 13:29:07 +01:00
c701d9cc8c toollib: use cmd mempool for list
When creating a list in 'context of command' - use proper mempool.

vg->vgmem is mempool related to VG metadata - and can be eventually
locked read-only when VG struct is shared.
2016-01-21 13:28:28 +01:00
fcbef05aae doc: change fsf address
Hmm rpmlint suggest fsf is using a different address these days,
so lets keep it up-to-date
2016-01-21 12:11:37 +01:00
cc53a23d82 cleanup: join if/else 2016-01-21 12:11:37 +01:00
3e09f916b4 man: show hidden pieces
W: manual-page-warning /usr/share/man/man8/lvm.8.gz 491: warning: macro `_cdata',' not defined

rpmlint actually notices we had few hidden word in man page.
the line cannot start with apostrophe as it has then a different
meaning.
2016-01-21 12:11:35 +01:00
640c45d5a4 man: dmsetup
Typo in CMD_UDEVCREATECOOKIE macro name noticed by rpmlint.
2016-01-21 12:10:26 +01:00
43b436398e configure: fix configure to set proper use_blkid_wiping if autodetected as disabled
If not using explicit --enable-blkid-wiping/--disable-blkid-wiping
configure option, the configure script tries to enable/disable blkid
wiping feature automatically based on blkid library version found.

The script incorrectly set default value for lvm.conf's
allocation/use_blkid_wiping" setting to "1" (enabled) if proper
blkid library version was not found or the version found was less
than the minimum required. It should be set to "0" in this case.
2016-01-21 10:01:34 +01:00
21028a7903 cleanup: reformat sentence about max sizes
The extent size must fits all blocks in 4294967295 sectors
(in 512b units) this is 1/2 KiB less then 2TiB.

So while previous statement 'suggested' 2TiB is still acceptable value,
make it clear it's not.

As now we support any multiples of 128KB as extent size -
values like 2047G will still 'flow-in' otherwise the largest power-of-2
supported value is 1TiB.

With 1TiB user needs 8388608 extents for 8EiB device.
(FYI such device is already unusable with todays glibc-2.22.90-27)

4GiB extent size is currently the smallest extent size which allows
a user to create 8EiB devices (with 2GiB  it's less then 8EiB).

TODO: lvm2 may possibly print amount of 'lost/unused space' on a PV,
since using such ridiculously sized extent size may result in huge
space being left unaccessible.
2016-01-20 13:44:47 +01:00
7b5a8f61a7 cleanup: drop extra cmd passed arg
Use vg->cmd when needed cmd struct.
2016-01-20 13:44:47 +01:00
b64703401d cleanup: relocate size assign
Directly set thin-pool size when thin data LV size changes.
2016-01-20 13:44:47 +01:00
ca878a3426 cleanup: adjust once 2016-01-20 13:44:47 +01:00
178cbb580a cleanup: update check function
Use display_lvname().
Use lv_is_lockd_sanlock_lv().
Order  'error' checks ahead of 'ignore' ones.
2016-01-20 13:44:47 +01:00
4b9ae55a8d cleanup: shuffle check of threshold
Check first threshold and then policy_amount.
2016-01-20 13:44:47 +01:00
c99ca6f430 cleanup: use log_print
Using log_print for ignoring message instead of log_warn.
Add some missing '.'.
2016-01-20 13:44:47 +01:00
2da7525c83 activation: remote node check doesn't work yet 2016-01-20 02:54:11 +00:00
509410bbbc clvmd: Initialise udev.
Since commit 2fc126b00d, the library
code requires udev to be initialised for device scanning and
clvmd can fail to find VGs if devices/external_device_info_source
is set to "udev".
2016-01-20 00:58:09 +00:00
2304286f68 activation: Add lv_is_active_remotely. 2016-01-19 22:01:59 +00:00
c812c2dbc7 locking: Add node parameter to query_resource. 2016-01-19 21:42:22 +00:00
7f6a1e6bba man: mention GPT id for LVM in pvcreate man page 2016-01-19 15:28:44 +01:00
2a4ef78c4a report: fix off-by-one error when reporting LV segment's metadata device extent count
Commit a3f484f812 used "-1" two times by
mistake for the extent count when reporting seg_metadata_le_ranges.
2016-01-19 14:44:06 +01:00
acf1e84e8c report: add note about seg_pe_ranges and seg_le_ranges in -o help 2016-01-19 14:30:21 +01:00
1341f83554 report: add seg_le_ranges report field 2016-01-19 14:30:21 +01:00
fccb1bb276 report: make devices, metadata_devices, seg_pe_ranges and seg_metadata_le_ranges fields consistent
There are two basic groups of fields for LV segment device reporting:
  - related to LV segment's devices: devices and seg_pe_ranges
  - related to LV segment's metadata devices: metadata_devices and seg_metadata_le_ranges

The devices and metadata_devices report devices in this format:
    "device_name(extent_start)"

The seg_pe_ranges and seg_metadata_le_ranges report devices in
this format:
    "device_name:extent_start-extent_end"

This patch reverts partly what commit 7f74a99502
(v 2.02.140) introduced in this area - it added [] for
hidden devices to mark them for all four fields mentioned above.

We won't be marking hidden devices in devices and metadata_devices
fields.

The seg_metadata_le_ranges field will have hidden devices marked -
it's new enough that we don't need to care about compatibility much
yet.

The seg_pe_ranges is old enough that we shouldn't be changing this
one - so we're reverting to not marking hidden devices here.
Instead, there's going to be a new field "seg_le_ranges" which
is going to replace the seg_pe_ranges and it will mark hidden devices -
this is going to be introduced in a patch later.

So in the end we'll end up with:

   (LV segment's devices)
   devices field with "device_name(extent_start)" format, not marking hidden devices
   seg_pe_ranges field with "device_name:extent_start-extent_end" format, not marking hidden devices (deprecated, new seg_le_ranges should be used instead for standardized format)
   seg_le_ranges field with "device_name:extent_start-extent_end" format, marking hidden devices

   (LV segment's metadata devices)
   metadata_devices field with "device_name:extent_start-extent_end" format, not marking hidden devices
   seg_metadata_le_ranges field with "device_name:extent_start-extent_end" format, marking hidden devices

Also, both seg_le_ranges and seg_metadata_le_ranges will honour the
report/list_item_separator setting which can be used to configure
the delimiter used for list items.

So, to sum it up, we will recommend using the new seg_le_ranges and
seg_metadata_le_ranges fields because they display devices with
standard extent range format, they can mark hidden devices and they
honour the report/list_item_separator setting.

We'll be keeping devices,seg_pe_ranges and metadata_devices fields
for compatibility.
2016-01-19 14:30:20 +01:00
b160b73800 report: change _format_pvsegs to return list instead of plain string, change associated report fields from STR to STR_LIST
The associated devices,metadata_devices,seg_pe_ranges and
seg_metadata_le_ranges are reported as genuine string lists now.
This allows for using the items separately in -S|--select
(so searching for subsets etc.) and also it allows for
configuring the separator using report/list_item_separator
which may be useful in scripts (however, we'll enable this
only for seg_le_metadata_ranges and not for devices,seg_pe_ranges
and seg_metadata_devices for compatibility reasons - see following
patch).
2016-01-19 14:17:41 +01:00
2ed324648e refactor: add 'delimiter' variable for non-default delimiter when reporting string list 2016-01-19 11:50:52 +01:00
48f270970f lvconvert: disallow test mode in shared VG
until test mode can be checked in all the necessary
locations related to lvmlockd to prevent making
actual changes.
2016-01-18 16:53:14 -06:00
6b3e402298 toollib: add comment about missing device
Add a comment in _process_pvs_in_vg() to document the
place where there have been problems with processing
PVs twice.

For a while we had a hacky workaround here where we'd
skip processing a PV if its device wasn't found in
all_devices (and !is_missing_pv since we want to
process PVs with missing devices.).  That workaround
was removed in commit 5cd4d46f because it was no
longer needed.

The workaround had originally been needed to prevent
a device from being processed twice when the PV had
no MDAs -- it would be processed once in its real VG
and then the workaround would prevent it from being
processed a second time in the orphan VG.

Wrongly appearing as an orphan likely happened because
lvmcache would consider the no-MDA PV an orphan unless
the real VG holding that PV was also in lvmcache.
This issue is also mentioned in pvchange where holding
the global lock allows VGs to remain in lvmcache so
PVs with 0 mdas are not considered orphans.

The workaround in _process_pvs_in_vg() was originally
intended for reporting commands, not for pvchange.
But, it was accidentally helping pvchange also because
the method described by the pvchange global lock
comment had been subverted by commit 80f4b4b8.
Commit 80f4b4b8 was found to be unnecessary, and was
reverted in commit e710bac0.  This restored the
intended global lock lvmcache effect to pvchange, and
it no longer relied on the workaround in toollib.
2016-01-18 16:09:22 -06:00
a3f484f812 report: Fix seg_pe_ranges LV sizes.
When reporting on LVs, take the end of the range from the size of the
underlying (hidden) LV rather than the logical size of the current
segment (that PVs use).
2016-01-18 22:04:43 +00:00
6d7dc87cb3 pvmove: use toollib
Previously, pvmove used the function find_pv_in_vg() which did the
equivalent of process_each_pv() by doing:

  find_pv_by_name() -> get_pvs() ->

  get_pvs_internal() -> _get_pvs() -> get_vgids() ->

  /* equivalent to process_each_pv */
  dm_list_iterate_items(vgids)
    vg = vg_read_internal()
    dm_list_iterate_items(&vg->pvs)

With the found 'pv', it would do vg_read() on pv_vg_name(pv),
and then do the actual pvmove processing.

This commit simplifies by using process_each_pv() and putting
the actual pvmove processing into the "single" function.
This eliminates both find_pv_by_name() and the vg_read().
The processing code that followed vg_read remains the same.

The return code for the pvmove command is not based on the
process_each_pv return code, but is based on the success/fail
conditions in the existing code.
2016-01-18 14:48:30 -06:00
5cd4d46f30 Revert "Revert "process_each_pv: remove unnecessary workaround""
This reverts commit 6d09c8c2c4.

Try again to remove the workaround.
2016-01-18 09:36:55 -06:00
06346eab84 lvmlockd: cosemtic improvements to logging
Also pass our name to sanlock so it appears in
the sanlock status output.
2016-01-18 09:35:21 -06:00
95ead96004 lvmlockd: fix lvb validation for conversion
Make the lvb validation rules for convert match
those for unlock (even though it would be very
unlikely or impossible for convert to deal with
zero lvb.)
2016-01-18 09:35:20 -06:00
54b41dcd53 pvchange, pvresize: fix lockd_gl() usage
When an orphan PV is changed/resized, the
lvmlockd global lock is converted from sh
to ex. If the command is changing two
orphan PVs, the conversion to ex should
be done only once.
2016-01-18 09:35:06 -06:00
1ee6af344b report: add kernel_cache_settings field
Existing cache_settings field displays the settings which are
saved in metadata. Add new kernel_cache_settings fields to display
the settings which are currently used by kernel, including fields
for which default values are used.

This way users have complete view of the set of cache settings
supported (and which they can set) and their values which are used
at the moment by kernel.

For example:

$  lvs -o name,cache_policy,cache_settings,kernel_cache_settings vg
  LV      Cache Policy Cache Settings                               KCache Settings
  cached1 mq    migration_threshold=1024,write_promote_adjustment=2 migration_threshold=1024,random_threshold=4,sequential_threshold=512,discard_promote_adjustment=1,read_promote_adjustment=4,write_promote_adjustment=2
  cached2 smq   migration_threshold=1024                            migration_threshold=1024
  cached3 smq   migration_threshold=2048
2016-01-18 14:42:29 +01:00
7f62777041 post-release 2016-01-16 02:12:10 +00:00
0faa27d4f5 pre-release 2016-01-16 02:11:21 +00:00
7559af2334 lvm2app: fix lvm2app to return either 0 or 1 for lvm_vg_is_{clustered,exported}
Fix lvm2app to return either 0 or 1 for lvm_vg_is_{clustered,exported},
including internal functions pvseg_is_allocated and vg_is_resizeable
which are not yet exposed in lvm2app but make them consistent with the
rest.
2016-01-15 14:42:18 +01:00
1752f5c31e lvmlockd: fixes for test mode
Get the test mode working (lvmlockd running with no
lock manager).
2016-01-14 16:01:29 -06:00
e710bac03d Revert "lvmcache: skip drop when vg_write lock is not held"
This reverts e28e22b9e1
The problem that that commit was fixing (pytest failure)
no longer appears with the current code, so the commit is
not needed.

That commit is a problem for pvchange, because it prevents
lvmcache from retaining VG metadata even while the global
lock is held.  pvchange holds the global lock to ensure
that VG metadata is kept in lvmcache throughout processing.
If the cache is not kept, a PV with zero MDAs will appear
first in its actual VG and then appear again in the orphan VG.
It wrongly appears a second time in the orphan VG only if
the actual VG is dropped from lvmcache.
2016-01-14 13:34:36 -06:00
b82d5ee092 report: add kernel_discards report field to display thin pool discard used in kernel
Thin pool discard mode set in metadata can be different from the one
actually used if any device underneath does not support that mode. Add
kernel_discard report field to make it possible to see this difference.
2016-01-14 16:54:12 +01:00
6d09c8c2c4 Revert "process_each_pv: remove unnecessary workaround"
This reverts commit be1b1f3d89.
2016-01-14 09:12:57 -06:00
88400b599e lvmanip: fix last commit and drop else
In last commit when removing if() branch
this 'else' now has to be dropped.
2016-01-14 11:55:47 +01:00
278c5509ee cleanup: order ac members 2016-01-14 11:34:05 +01:00
c9a813bff8 cleanup: spaces 2016-01-14 11:34:05 +01:00
7d2b7f2bd8 cleanup: replace log_warn 2016-01-14 11:34:05 +01:00
2567d03e95 cleanup: explicit prohibition for virtual segs
Internal _alloc_init() is only called from allocate_extents(),
which already does prevent usage of virtual segments.

So mark as internal error early and do not process it any further.
2016-01-14 11:34:05 +01:00
4310dfd4e1 cleanup: simplier formula 2016-01-14 11:34:05 +01:00
ebcfd09ba9 cleanup: more readable check 2016-01-14 11:34:05 +01:00
753a496348 snapshot: relocate alloc_snapshot_seg
Move alloc_snapshot_seg to snapshot_manip and make it local static.
2016-01-14 11:34:05 +01:00
8857b22764 segtype: check for activation
Before setting static variable with check passed state,
detect if we are allowed to talk to driver.
2016-01-14 11:34:05 +01:00
43897239b3 lvresize: check for poolmetadatasize arg earlier
Since we check for poolmetadatasize, we need to detect it before
actual test.
2016-01-14 11:34:04 +01:00
526297296f lvmanip: add lv_is_snapshot
Add new test for  lv_is_snapshot().
Also move few other bitchecks into same place as remaining bit tests.

TODO: drop lv_is_merging_origin() and keep using lv_is_merging().
2016-01-14 11:34:04 +01:00
01228b692b vgcfgrestore: Retain allocatable PV attribute.
pvchange -xn was getting lost.
All PVs were set to allocatable again after restore.

Moved setting ALLOCATABLE_PV outside pv_setup().
2016-01-14 00:46:45 +00:00
9e9c757541 vgchange: fix lockd_gl results
The wrong error value was being checked from lockd_gl()
in two cases.

Clarify the use of lockd_gl() in the lock-start case.
2016-01-13 16:40:02 -06:00
1b1f42b490 lvmlockd: fix exit code
libdaemon uses 1 for success
2016-01-13 16:40:02 -06:00
be1b1f3d89 process_each_pv: remove unnecessary workaround
The problem addressed by this workaround no longer
seems to exist, so remove it.  PVs with no mdas
no longer appear in both their actual VG and in
the orphan VG.
2016-01-13 10:46:04 -06:00
63d59254d9 lv: fix check for NULL origin_lv in _do_lv_origin_dup, cleanup _do_lvconvert_lv_dup 2016-01-13 17:11:05 +01:00
04d1a8a5e4 cleanup: rename 'invisible devices' to 'hidden devices' 2016-01-13 16:43:25 +01:00
939d296525 conf: fix 'the volume list' vs 'volume list' and '@*' 2016-01-13 15:47:26 +01:00
9a81881965 cleanup: rename 'invisible devices' to 'hidden devices' 2016-01-13 15:37:15 +01:00
1417ed304b cleanup: rename 'invisible devices' to 'hidden devices' 2016-01-13 15:22:46 +01:00
d2d5c5e6c9 WHATS_NEW: reports and invisible devices 2016-01-13 14:45:49 +01:00
efab21b411 test: add report-invisible.sh test 2016-01-13 14:37:09 +01:00
c66a83fdc3 tests: update tests to deal with invisible devices consistently 2016-01-13 13:55:24 +01:00
84a9f750fe cleanup: cleanup lv.h and put fns into categories for better readability 2016-01-13 12:17:00 +01:00
293abbb8d2 conf: update command_profile_template.profile.in 2016-01-13 12:16:58 +01:00
53b355a24b conf: regenerate 2016-01-13 12:01:55 +01:00
e168b5de75 conf: add report/mark_invisible_devices 2016-01-13 12:01:10 +01:00
7f74a99502 lv: use brackets for invisible devices when formatting device segments
Include brackets for the name if the dev is invisible.
This change applies to all callers of _format_pvsegs fn:
  - lvseg_devices (the "lvs -o devices")
  - lvseg_metadata_devices (the "lvs -o metadata_devices)
  - lvseg_seg_pe_ranges (the "lvs -o seg_pe_ranges")
  - lvseg_seg_metadata_le_ranges (the "lvs -o seg_metadata_le_ranges")
2016-01-13 11:20:04 +01:00
f1fe7af014 lv: add common lv_pool_lv fn for use in report and dup, use brackets for invisible devices
The common lv_pool_lv fn avoids code duplication and also
the reporting part now uses _lvname_disp and _uuid_disp to display
name and uuid respectively, including brackets for the name if the
dev is invisible.
2016-01-13 11:20:01 +01:00
42fcbc1fd4 lv: add common lv_metadata_lv fn for use in report and dup, use brackets for invisible devices
The common lv_metadata_lv fn avoids code duplication and also
the reporting part now uses _lvname_disp and _uuid_disp to display
name and uuid respectively, including brackets for the name if the
dev is invisible.
2016-01-13 11:19:58 +01:00
cdbf76b2f0 lv: add common lv_data_lv fn for use in report and dup, use brackets for invisible devices
The common lv_data_lv fn avoids code duplication and also
the reporting part now uses _lvname_disp and _uuid_disp to display
name and uuid respectively, including brackets for the name if the
dev is invisible.
2016-01-13 11:19:55 +01:00
d50cd9d8d7 lv: add common lv_mirror_log_lv for use in report and dup, use brackets for invisible devices
The common lv_mirror_log_lv fn avoids code duplication and also
the reporting part now uses _lvname_disp and _uuid_disp to display
name and uuid respectively, including brackets for the name if the
dev is invisible.
2016-01-13 11:19:51 +01:00
aae45a1f21 lv: add common lv_origin_lv fn for use in report and dup, use brackets for invisible devices
The common lv_origin_lv fn avoids code duplication and also
the reporting part now uses _lvname_disp and _uuid_disp to display
name and uuid respectively, including brackets for the name if the
dev is invisible.
2016-01-13 11:19:45 +01:00
1bd83814ce lv: add common lv_convert_lv fn for use in report and dup, use brackets for invisible devices
The common lv_convert_lv fn avoids code duplication and also
the reporting part now uses _lvname_disp and _uuid_disp to display
name and uuid respectively, including brackets for the name if the
dev is invisible.
2016-01-13 11:16:37 +01:00
9e336582f4 man lvmlockd: mention pvmove restriction 2016-01-12 12:01:53 -06:00
0c6946b4ce pvmove: disallow moving PVs under sanlock leases
Fail with an error message if pvmove tries to move PVs
under the lvmlock LV.
2016-01-12 11:53:33 -06:00
176b4aaebe report: use proper string reference in _string_disp call for _cache_policy_disp fn 2016-01-12 16:14:23 +01:00
1a3ee6402e test: conditional skip of auto-activation bg polling test
if dm-snapshot-merge target not present skip whole test
2016-01-12 13:32:23 +01:00
d1e30ff0ba vgchange: drop redundant check
check for background polling option is performed from
within vgchange_background_polling routine as well.
2016-01-12 11:41:41 +01:00
d09246a07d test: add test for autoactivation regression
add test for a regression fixed in
40701af969
2016-01-12 11:40:43 +01:00
40701af969 pvscan: restore polling in autoactivation handler
This commit fixes regression in auto-activation code introduced
in commit: c26d81d6e6.

- resolves rhbz1295562
2016-01-12 11:40:43 +01:00
d6cf83968c report: use brackets to signify LVs which are not visible when reporting lv_parent
Use common _lvname_disp to report lv_parent. The _lvname_disp
takes care of properly marking LVs which are not visible - such
LVs are always enclosed in brackets when reported within any
other field.

For example, thin pool over RAID.

Before:

$ lvs -a -o name,lv_parent,data_lv,metadata_lv vg
  LV                          Parent           Data               Meta
  cache_pool                                   [cache_pool_tdata] [cache_pool_tmeta]
  [cache_pool_tdata]          cache_pool
  [cache_pool_tdata_rimage_0] cache_pool_tdata
  [cache_pool_tdata_rimage_1] cache_pool_tdata
  [cache_pool_tdata_rmeta_0]  cache_pool_tdata
  [cache_pool_tdata_rmeta_1]  cache_pool_tdata
  [cache_pool_tmeta]          cache_pool
  [cache_pool_tmeta_rimage_0] cache_pool_tmeta
  [cache_pool_tmeta_rimage_1] cache_pool_tmeta
  [cache_pool_tmeta_rmeta_0]  cache_pool_tmeta
  [cache_pool_tmeta_rmeta_1]  cache_pool_tmeta
  [lvol0_pmspare]

With this patch applied:

$ lvs -a -o name,lv_parent,data_lv,metadata_lv vg
  LV                          Parent             Data               Meta
  cache_pool                                     [cache_pool_tdata] [cache_pool_tmeta]
  [cache_pool_tdata]          cache_pool
  [cache_pool_tdata_rimage_0] [cache_pool_tdata]
  [cache_pool_tdata_rimage_1] [cache_pool_tdata]
  [cache_pool_tdata_rmeta_0]  [cache_pool_tdata]
  [cache_pool_tdata_rmeta_1]  [cache_pool_tdata]
  [cache_pool_tmeta]          cache_pool
  [cache_pool_tmeta_rimage_0] [cache_pool_tmeta]
  [cache_pool_tmeta_rimage_1] [cache_pool_tmeta]
  [cache_pool_tmeta_rmeta_0]  [cache_pool_tmeta]
  [cache_pool_tmeta_rmeta_1]  [cache_pool_tmeta]
  [lvol0_pmspare]
2016-01-11 15:34:35 +01:00
f03a21f5b8 cleanup: use _field_set_value and _string_disp consistently in report.c
Do not mix dm_report_field_set_value and _field_set_value and
use single function call throughout for clarity. The same applies
for dm_report_field_string and _string_disp.
2016-01-11 15:01:42 +01:00
a83d611a86 report: fix invalid memory read when reporting cache LV policy name
Fix regression caused by commit c2d4330f27
which removed the dm_pool_strdup for the cache policy name in
_cache_policy_disp report function.

This regression was hit with buffered reporting only (which is
used by default). The reason is that for buffered reporting, we're
iterating over LVs in VG (process_each_lv) while gathering
all the information that is needed for the report. In this case,
the LV's cache policy name has not been duped, but only the pointer
to the original VG buffer was stored. When the LV iteration finished,
the VG buffer was freed and any report to output called later
(dm_report_output call) accessed already freed VG data.

This didn't appear if unbuffered reporting was used (--unbuffered)
because in this case, the data were reported to output as
soon as they were processed, hence it was reported to output
before the VG data was freed.
2016-01-11 12:51:08 +01:00
0dac4f09b4 post-release 2016-01-08 18:51:08 +00:00
04b82a8126 pre-release 2016-01-08 18:46:41 +00:00
580c67486f document commits since last release 2016-01-08 09:53:58 -06:00
8d11468ab2 man: lvs: document F,D and M thin pool health status chars for lv_attr in lvs man page 2016-01-08 15:47:01 +01:00
4304a95dfd lvmdump: also add lvm2-activation{-early,-net}.service systemd status for lvmdump -s
The lvm2-activation{-early,-net}.service systemd unit statuses were missing
in dump gathered by lvmdump -s. These are quite important when debugging
scenarios with systemd environment and where lvmetad is not used.
2016-01-04 15:12:25 +01:00
124b490fe6 lvmlockd: update VG lock version earlier
Have commands send lvmlockd the update message
in vg_write instead of vg_commit, so that it's
not done while LVs are suspended.  If the vg_write
is not committed, and the seqno sent to lvmlockd
is not used, then lvmlockd can detect this when
the next update uses the same seqno.
2015-12-15 16:14:49 -06:00
796461a912 vgrename: use process_each_vg
Use process_each_vg() to lock and read the old VG,
and then call the main vgrename code.

When real VG names are used (not a UUID in place of the
old name), the command still pre-locks the new name
(when strcmp wants it locked first), before calling
process_each_vg on the old name.

In the case where the old name is replaced with a UUID,
process_each_vg now translates that UUID into the real
VG name, which it locks and reads.  In this case, we
cannot do pre-locking to maintain lock ordering because
the old name is unknown.  So, in this case the strcmp
based lock ordering is suppressed and the old name is
always locked first.  This opens a remote chance for
lock ordering conflict between racing vgrenames between
two names where one or both commands use the UUID.
2015-12-14 14:26:47 -06:00
37bd35bc3d pvscan: Remove duplicate filter wipe.
Also always clear the internal lvmcache after rescanning, and
reinstate a test for --trustcache so that 'pvs --trustcache'
(for example) avoids rescanning.
2015-12-14 20:14:59 +00:00
92e1422707 process_each_pv: do full scan earlier to find new devices
Before commit c1f246fedf,
_get_all_devices() did a full device scan before
get_vgnameids() was called.  The full scan in
_get_all_devices() is from calling dev_iter_create(f, 1).
The '1' arg forces a full scan.

By doing a full scan in _get_all_devices(), new devices
were added to dev-cache before get_vgnameids() began
scanning labels.  So, labels would be read from new devices.
(e.g. by the first 'pvs' command after the new device appeared.)

After that commit, _get_all_devices() was called
after get_vgnameids() was finished scanning labels.
So, new devices would be missed while scanning labels.
When _get_all_devices() saw the new devices (after
labels were scanned), those devices were added to
the .cache file.  This meant that the second 'pvs'
command would see the devices because they would be
in .cache.

Now, the full device scan is factored out of
_get_all_devices() and called by itself at the
start of the command so that new devices will
be known before get_vgnameids() scans labels.
2015-12-14 10:02:29 -06:00
1be56e46c4 post-release 2015-12-14 12:25:48 +00:00
3e8126a66a pre-release 2015-12-14 12:24:21 +00:00
4aa9e99a10 Change messages from verbose to debug
These messages about outdated PVs should not
be verbose because they always appear, even
when there are no outdated PVs.
2015-12-11 15:28:46 -06:00
3e48354f2d cleanup: add missing WHATS_NEW 2015-12-11 20:15:57 +01:00
07b9147ced tests: check lvrename of stacked cache pool 2015-12-11 20:15:57 +01:00
7a4badc07f fix static linking
Static linking fails currently, as -lm and -lpthread are missing:

gcc -O2  -fPIC -O2  -L../libdm -L../lib -L../libdaemon/client -static
-L../libdm/ioctl \
      -o dmsetup.static dmsetup.o -ldevmapper    -lrt
../libdm/ioctl/libdevmapper.a(libdm-stats.o): In function
`dm_stats_create_region':
libdm-stats.c:(.text+0x2d69): undefined reference to `log10'
libdm-stats.c:(.text+0x2d6e): undefined reference to `lround'
../libdm/ioctl/libdevmapper.a(pool.o): In function `dm_pool_create':
pool.c:(.text+0x134): undefined reference to `pthread_mutex_lock'
pool.c:(.text+0x14f): undefined reference to `pthread_mutex_unlock'

Signed-off-by: Riku Voipio <riku.voipio@linaro.org>
2015-12-11 20:15:51 +01:00
0688dbbc53 tests: fix logging
Actually  file redirection must be before stderr redir.
2015-12-10 21:01:24 +01:00
cd8e95d933 lvrename: always allow to rename pools
Since we mark cache-pool as 'hidden/private' while it is in-use,
we may still allow user to change it's name.

It should not cause any harm and user may prefer better naming
for a cache-pool in use.
2015-12-10 21:01:24 +01:00
bf4b74c5eb cache: support stacked rename
Preserve skip_pool flag when running for_each_sub_lv() so
lvrename continues to work when thin-pool is using cached
data LV.
2015-12-10 21:01:24 +01:00
dcb26b5f13 lvmlockd: reconnect to lvmetad if it's restarted
If lvmetad is restarted after lvmlockd has connected
to it, then lvmlockd should reconnect.
2015-12-10 10:50:19 -06:00
bdba4e7a93 lvrename: move the lvmlockd LV lock
The function it was in is used for various
internal renaming of hidden LVs where a lock
from lvmlockd does not apply.
2015-12-09 11:59:49 -06:00
dcd946e95a dmeventd: Don't trust fifo with wrong attrs.
If an existing fifo has the wrong attributes it cannot be trusted
so we must unlink it and recreate it correctly.
(Replaces 2c8d6f5c90: if the other end of
the fifo already got opened while its mode was insecure, delaying the
chmod isn't going to make any difference!)
2015-12-08 01:48:17 +00:00
94dab390ef dmeventd: Extend checks on client socket.
Reinstate and extend checks removed by e1b111b02a.

The code has always assumed that only root has access to the directory
containing the fifos and that they are under the complete control of
dmeventd code.  If anything is found not to be as expected, then open()
should certainly not be attempted!
2015-12-08 00:59:39 +00:00
00bab9d9cd post-release 2015-12-05 15:36:22 +00:00
063b353b28 pre-release 2015-12-05 15:33:19 +00:00
fedf15ffb0 tests: extend test 2015-12-04 22:10:30 +01:00
748b8158b5 archiver: fix reporting for check_current_backup
It's getting a bit more complex here.

Basic idea behind is - check_current_backup() should not
log error when a user is using a read-only filesystem,
so e.g.  vgscan  will not report any error when it tries
to take missing backup.

We still have cases when error could be reported though,
e.g. the backup this would be a symbolic link, but these
are rather misconfiguration and unexpected case.
2015-12-04 22:10:30 +01:00
8b16efd17c debug: correct stack tracing
Here the 'goto' is correct path, as  !device_is_usable
is traceable with <backtrace>.

Keep the 'stack' for unusable device.
2015-12-04 22:10:30 +01:00
45781161f4 libdm: add some doc for mirror status
Comment content of struct for mirror status.
2015-12-04 22:10:30 +01:00
c24d913c47 lvconvert: Reinstate raid merge after splitmirror.
After commit 46c8d6bb8a
(lvconvert: Improve message for raid without -m)
2015-12-03 17:40:10 +00:00
89418c1253 tests: check read-only backup archive 2015-12-03 18:17:45 +01:00
d2524315e6 vgextend: reinstantiate archiving
Since commit f5d06efbab we lost archiving.
Restore it now with process_each_vg.
2015-12-03 18:17:45 +01:00
e7978c5ab6 cleanup: drop log_suppress(2) usage
No longer need to use  log_suppress(2) instance so dropped.
2015-12-03 18:02:34 +01:00
f40b3ba1e9 archiver: inital change toward proper logging
We have to modes of  'archive()' usage -
1. compulsory - fail stops command and user may try '-An' option
to do a command.

2. non-compulsory - some fails in archiving are ignorable (i.e.
read-only filesystem where archive dir is located).

Those 2 cases needs to be properly handle - i.e. the non-compulsory
logging should not be tampering  error logging message production.

So more work here is needed
2015-12-03 18:01:45 +01:00
20acc66a23 log: use full buffer size for printf
Pass full buffer size to printf() function - no reason to make
buffer 1 char smaller.

Also rename locn buffer to message buffer directly since it's
not used for anything else.

TODO: we may use same buffer also for 'buf[]' since there is
no collision - so may safe 1K on stack usage.
2015-12-03 18:01:42 +01:00
20483ead5b cleanup: use try_id_read_format
Better then using log_suppress in this case.
2015-12-03 18:00:54 +01:00
c15c44a492 uuid: add id_read_format_try
Provide id_read_format() functionality without log_error
when ID is not valid one - it will just return 0.

Does not need to use log_suppress() then.
2015-12-03 18:00:38 +01:00
aec58c8620 lvconvert: Reinstate mirror to raid conversions.
Reinstate conversions from mirror to raid stopped
by commit 46c8d6bb8a
(lvconvert: Improve message for raid without -m).
2015-12-03 14:40:14 +00:00
3bbf89e9ec man lvm: add section about unique VG names 2015-12-02 10:37:25 -06:00
61573bd197 toollib: only interpret vgname arg as uuid for vgrename
In general, --select should be used to specify a VG by UUID,
but vgrename already allows a uuid to be substituted for
the name, so continue to allow it in that case.
2015-12-01 15:50:14 -06:00
166adf0e1f toollib: allow VG UUID to be used in place of VG name
If the VG arg from the command line does not match the
name of any known VGs, then check if the arg looks like
a UUID.  If it's a valid UUID, then compare it to the
UUID of known VGs.  If it matches the UUID of a known VG,
then process that VG.
2015-12-01 12:08:24 -06:00
67763a9bec lvresize: use process_each_vg
No functional change.
2015-12-01 11:01:26 -06:00
5bbbd37f41 lvrename: use process_each_vg
No functional change.
2015-12-01 09:54:33 -06:00
f7571eb287 lvcreate: use process_each_vg
No functional change.
2015-12-01 09:36:52 -06:00
ea74215fa1 vgextend: pass single vgname as process_each_vg arg
Pass the single vgname as a new process_each_vg arg
instead of setting a cmd flag to tell process_each_vg
to take only the first vgname arg from argv.

Other commands with different argv formats will be
able to use it this way.
2015-12-01 09:36:45 -06:00
3bcdf5d14b lvmcache: change duplicate VG name warnings to verbose
When two different VGs with the same name exist,
they are both stored in lvmcache using the vginfo->next
list.  Previously, the code would print warnings (sometimes)
when adding VGs to this list.  Now the duplicate VG names
are handled by higher level code, so this list no longer
needs to print warnings about duplicate VG names being found.
2015-12-01 09:30:23 -06:00
88cef47b18 vg_read: look up vgid from name
After recent changes to process_each, vg_read() is usually
given both the vgname and vgid for the intended VG.

However, in some cases vg_read() is given a vgid with
no vgname, or is given a vgname with no vgid.

When given a vgid with no vgname, vg_read() uses lvmcache
to look up the vgname using the vgid.  If the vgname is
not found, vg_read() fails.

When given a vgname with no vgid, vg_read() should also
use lvmcache to look up the vgid using the vgname.
If the vgid is not found, vg_read() fails.

If the lvmcache lookup finds multiple vgids for the
vgname, then the lookup fails, causing vg_read() to fail
because the intended VG is uncertain.

Usually, both vgname and vgid for the intended VG are passed
to vg_read(), which means the lvmcache translations
between vgname and vgid are not done.
2015-12-01 09:18:48 -06:00
1e43ec15ce toollib: remove unused function 2015-12-01 09:10:01 -06:00
aa4932674a process_each: resolve duplicate VG names
If two different VGs with the same name exist on the system,
a command that just specifies that ambiguous name will fail
with a new error:

$ vgs -o name,uuid
  ...
  foo qyUS65-vn32-TuKs-a8yF-wfeQ-7DkF-Fds0uf
  foo vfhKCP-mpc7-KLLL-Uh08-4xPG-zLNR-4cnxJX

$ lvs foo
  Multiple VGs found with the same name: foo
  Use the --select option with VG UUID (vg_uuid).

$ vgremove foo
  Multiple VGs found with the same name: foo
  Use the --select option with VG UUID (vg_uuid).

$ lvs -S vg_uuid=qyUS65-vn32-TuKs-a8yF-wfeQ-7DkF-Fds0uf
  lv1 foo ...

This is implemented for process_each_vg/lv, and works
with or without lvmetad.  It does not work for commands
that do not use process_each.

This change includes one exception to the behavior shown
above.  If one of the VGs is foreign, and the other is not,
then the command assumes that the intended VG is the local
one and uses it.
2015-12-01 09:09:55 -06:00
4ff2583dc5 process_each: always use list of vgnames on system
This makes process_each_vg/lv always use the list of
vgnames on the system.  When specific VGs are named on
the command line, the corresponding entries from
vgnameids_on_system are moved to vgnameids_to_process.

Previously, when specific VGs were named on the command
line, the vgnameids_on_system list was not created, and
vgnameids_to_process was created from the arg_vgnames
list (which is only names, without vgids).

Now, vgnameids_on_system is always created, and entries
are moved from that list to vgnameids_to_process -- either
some (when arg_vgnames specifies only some), or all (when
the command is processing all VGs, or needs to look at
all VGs for checking tags/selection).

This change adds one new lvmetad lookup (vg_list) to a
command that specifies VG names.  It adds no new work
for other commands, e.g. non-lvmetad commands, or
commands that look at all VGs.

When using lvmetad, 'lvs foo' previously sent one
request to lvmetad: 'vg_lookup foo'.
Now, 'lvs foo' sends two requests to lvmetad:
'vg_list' and 'vg_lookup foo <uuid>'.

(The lookup can now always include the uuid in the request
because the initial vg_list contains name/vgid pairs.)
2015-12-01 09:09:49 -06:00
68e2ea11a3 mirror: fix condition
Recent patch tested wrong condition for error
2015-12-01 13:59:20 +01:00
86e7894ecc cleanup: use dm_get_status_mirror
Use libdm function to parse mirror status report.
2015-12-01 13:03:16 +01:00
6336ef98d4 lib: pass mem pool to check_transient_status
check_transient_status() may need to allocate some memory,
so pass in already existing mem pool.
2015-12-01 13:01:28 +01:00
c717ea5fc0 tests: unit test for mirror status 2015-12-01 13:00:52 +01:00
fa87979004 libdm: introduce dm_get_status_mirror
Add missing function to parse mirror status.
2015-12-01 13:00:43 +01:00
46c8d6bb8a lvconvert: Improve message for raid without -m. 2015-11-30 22:36:05 +00:00
eb22f7c8f7 lvmcache: new function to check if VG is foreign
When not using lvmetad, this uses the system_id field in
the cached vginfo structs that are populated during a scan.

When using lvmetad, this requests the VG from lvmetad, and
checks the system_id field in the returned metadata.
2015-11-30 11:54:56 -06:00
05ac836798 system_id: refactor check for allowed system_id
Refactor the code that checks for an allowable system_id
so that it can be used from other places.
2015-11-30 11:46:55 -06:00
d3ca18e489 lvmcache: include system_id in vginfo cache
Save system_id just like creation_host and lock_type
strings in vginfo cache.
2015-11-30 11:32:17 -06:00
1f357532bb lvmetad: include both vgid and vgname in lookup request
When the command already knows both the vgid and vgname,
it should send both to lvmetad for a more exact request,
and it can save lvmetad the work of a name lookup.
2015-11-30 10:57:30 -06:00
cd4d2cff97 post-release 2015-11-28 01:29:00 +00:00
b4a3aaf910 pre-release 2015-11-28 01:25:53 +00:00
1fb8d746d6 tests: make unit testing usable again
Make unit tests usable/compilable with newer header files.
Add 'initial' dmlist_t  for list tests.
More will come...
2015-11-27 11:22:21 +01:00
ec647f1d43 cleanup: clean gcc shadow declaration of version warning 2015-11-26 21:52:22 +01:00
4afe43e1a3 debug: show LV name where dlid creation failed 2015-11-26 21:52:05 +01:00
922fccc656 cleanup: using display_lvname
Use for showing vgname/lvname in messages.
No functional change.
2015-11-26 09:27:37 +01:00
b7b59ad932 cleanup: remove unused code
Remove long outstand unused code lines, which were already
been obsoleted by other code.

Statuses and snapshot tree creation is already handled differently.

Also drop some 'extra' log_error() and use only stack;
since error has already been reported.
2015-11-26 09:27:37 +01:00
528695ec20 cleanup: avoid allocation for vg_name
Since we do not use dev_manager in a way we would have destroyed VG
content while  in-use - we could safely keep just pointer.
So dropping strdup.

Also it seems we actually no longer use vg_name for anything
so it may possibly go away completely unless it would be useful
for debugging...
2015-11-26 09:27:37 +01:00
d582be43d4 libdm: const raid params and error for unsupported type
Accept const struct with raid params (No API change).
Also add extra error message when raid type is unsupported.
2015-11-26 09:27:04 +01:00
1ea8afd3ca lvmconfig: add --sinceversion for --type new
Just for convenience to display all new configuration settings
introduced since given version (before, there was only --atversion
to display settings introduced in concrete version).

For example:
	$ lvmconfig --type new --sinceversion 2.2.120
	allocation {
		# cache_mode="writethrough"
		# cache_settings {
		# }
	}
	global {
		use_lvmlockd=0
		# lvmlockd_lock_retries=3
		# sanlock_lv_extend=256
		use_lvmpolld=1
	}
	activation {
	}
	# report {
		# compact_output_cols=""
		# time_format="%Y-%m-%d %T %z"
	# }
	local {
		# host_id=0
	}
2015-11-25 14:12:12 +01:00
66c7fa4a44 cleanup: rename lv_ondisk to lv_committed
Patch has no functional change.
2015-11-25 11:39:26 +01:00
4312b09635 cleanup: change ondisk committed
Patch has no functional change.
2015-11-25 11:39:26 +01:00
d9faf85987 cleanup: rename vg_ondisk to vg_committed
Unifying terminology.

Since all the metadata in-use are ALWAYS on disk - switch
to terminology  committed and precommitted.

Patch has no functional change inside.
2015-11-25 11:11:21 +01:00
0285066e10 thin: fix previous update of partial tree building
We do want to preserve 'active' thin-pool,
so add this 'fake' layer only when activating.

TODO:  think how to use thin-pool without fake LV layer.
2015-11-24 23:24:11 +01:00
8d86c5db03 tests: improve teardown
Do not try to execute vgremove, when test has left suspended devices.
2015-11-24 11:29:28 +01:00
a220939d9e tests: data correctness after thin-pool resize 2015-11-24 11:29:27 +01:00
9243877ea1 cleanup: use display_lvname
Switch debug msg to use display_lvname.
Link to VG early, so we have access to VG from LV.
2015-11-23 23:42:59 +01:00
5e50e5f0b4 thin: skip detach preload from pools
lv preload for detached LVs started to be used also
for various other types which just happens to pass through
weak if() condition.

TODO: find here better solution to rather explicitly check
for types we really need to preload.
2015-11-23 23:42:59 +01:00
6d6c233768 cleanup: move towards using direct LV pointers
We do not won't to 'expose'  internals of VG struct.
ATM we use lists to keep all LVs - we may want to switch
to better struct for quicker 'search'.

Since we do not need 'lists' but always actual LV,
switch find_lv_in_vg_by_lvid() to return LV,
and replaces some use case of  find_lv_in_vg()
with 'better' working find_lv() which already
returns LV.
2015-11-23 23:42:59 +01:00
94c9453659 thin: work with active thin-pool
When 'lvextend -L+XX vg/thinpool'  do not leave inactive table
loaded for 'wrapping' LV on top of resized thin-pool
(ATM we use linear  LV for this with same size as thin-pool).
2015-11-23 23:41:36 +01:00
15be97d76b memlock: add more libs on ignore list
Udev recently start to 'link-in' major amount of useless libs.
(Seem to be faulty 'systemd' link-in all issue)
Anyway - avoid locking those libs in RAM.
2015-11-23 23:39:01 +01:00
6ca5447e0c libdm: enhance thin-pool preload
When preloading thin-pool device node for already
existing/running thin-pool do not resume such thin-pool.

This allows to properly schedule commit point for metadata,
when thin-pool data or metadata volume is resized.
2015-11-23 23:34:46 +01:00
ddbf0075b1 libdm: drop extra space from cache target line
Extra space between 'cache' target and metadata device caused
string comparation being not equal and thus always causing
table reload even when uneeded.
2015-11-23 23:33:37 +01:00
fe64d3a2e2 man lvmcache: include chunk size 2015-11-23 11:57:41 -06:00
c026846739 post-release 2015-11-23 03:40:34 +00:00
369bc264b0 pre-release 2015-11-23 03:37:54 +00:00
da50f8bee6 tests: more cache conversion checks 2015-11-19 14:40:49 +01:00
795616a87b cache: lvconvert repairs only thin pools
Avoid internal error message where thin pool repair code tries to
fix cache pool - was catched later in code stack, so rather
catch this early and make the repair function exlusive
to thin pools.

So far we have no code for repairing cache pools
(other then the automatic during activation/deactivation).
2015-11-19 14:40:24 +01:00
d1608345df cache: enable raid conversion for _cdata and _cmeta
Since thin-pool supports convertion of data and metadata LV,
enable the same for cache data and metadata LV.
2015-11-19 14:38:36 +01:00
6f002c29a5 tests: stacktrace on skip if message is empty 2015-11-19 12:18:33 +01:00
2a23550cf3 tests: add missing --skip option and S env.variable 2015-11-19 12:00:59 +01:00
0614c63579 cleanup: cast resulting value explicitely 2015-11-19 11:59:19 +01:00
0b2be60497 cleanup: add stack traces 2015-11-18 22:17:26 +01:00
e2b00b0a89 cleanup: use display_lvname in pmspare
Just switch to use display_lvname().
Also squeeze possibly failing strncpy into INTERNAL_ERROR
as lvname always should fit.
2015-11-18 22:17:26 +01:00
0a2cadf6b8 libdm: report: consolidate use of string list selection structures 2015-11-18 10:54:09 +01:00
7b11ef6de0 tests: update lvmcache-exercise
To handle multiple VGs with the same name.
Simply using the VG name is ambiguous, and
lvmetad requires the VG uuid be used to
specify which one is meant.
2015-11-17 12:12:17 -06:00
6167f5da10 coverity: trying different model
Model reseting of given set, but it still makes
FD_SET to think it's accessing uninitialized value.

Maybe model also FD_SET.
2015-11-17 19:01:25 +01:00
83661c8f7f cleanup: use embeded list
Skip pointer and put list into selection_str_list.
2015-11-17 19:01:25 +01:00
6e71d3fbde cleanup: more readable code
Simplify if() expression.
Rename 'this' to 'vg'..
2015-11-17 19:01:25 +01:00
d8049dd17a cleanup: add some test for NULL
Coverity here is a bit 'blind' here and cannot resolve which
code paths are actually able to hit this code path.
(It's using 'statistic' to resolve all possible paths,
and it's not scanning 'individual' code paths.)

This just cleans warns and add 'cheap' tests.
2015-11-17 19:01:25 +01:00
011dd82050 cleanup: do not call vg_read with NULL mda
Use 'mda' instead of NULL to quite Coverity warn.
However this code seems to be actually not even possible to hit.
With proper analysis it may possibly be dropped from code to
simplify logic.
2015-11-17 19:01:25 +01:00
121341e52c cleanup: unify NULL custom check
Unify testing of NULL custom pointer.
Resolve 'factor' only in required if() branch.
2015-11-17 19:01:25 +01:00
cad3568def raid: drop unneeded NULL test
Skip testing target_pvs for NULL, we already
dereference it in many other places.
If check would ever be needed - it needs to be
in front of _raid_extract_images().
2015-11-17 19:01:25 +01:00
51dfba002b libdm: update error message
Correcting error message.
2015-11-17 19:01:25 +01:00
931fede81b hash: change name of new lookup function 2015-11-17 11:59:44 -06:00
4d37db123d lvmetad: improve error message for VGs with same name 2015-11-17 10:35:42 -06:00
485d2ca945 lvmetad: different style for hash functions
In lookup, return a count of entries with the
same key rather than the value from a second
entry with the same key.

Using some slightly different names.
2015-11-17 10:27:16 -06:00
d42cedae58 lvmetad: add error explaining duplicate VG names
When a VG name lookup fails because the name matches
multiple VGs, return an explanatory error.
2015-11-16 16:25:49 -06:00
7d1c9e1d5a lvmetad: fix some error logging
For some errors old_meta may not be set, so
check before logging it.
2015-11-16 15:13:26 -06:00
68c386cce7 lvmetad: use lookup_withval in another location
Simply use lookup_withval right away rather than doing a
standard lookup, checking for the wrong mapping, then
repeating with lookup_withval to get the right mapping.
2015-11-16 15:13:22 -06:00
4a984cabc4 lvmetad: remove unneeded FIXME
This case is now handled correctly.
2015-11-16 13:44:57 -06:00
920a281994 hash: add comment about multiple values 2015-11-16 11:02:25 -06:00
b6a45963e3 libdm: fix check of pointer
Ahhh being blind here - wanted to check the pointer before dereference
not a dereferenced one.
2015-11-16 13:10:24 +01:00
2a2487f02f libdm: better error reporting from dm_split_lvm_name
Report errors from all error paths correctly.
Validate passed args before dereferencing them.
2015-11-16 13:09:53 +01:00
5d4f5873a9 coverity: model FD_ZERO
Coverity is not able to understand assembly language in
system's header file, so provide model for such macro.

Note: to really see model in-use: #nodef FD_ZERO model_FD_ZERO
need to go to coverity/config/user_nodefs.h
2015-11-16 01:16:11 +01:00
8ebf2b0611 debug: lvconvert add missing display_lvname
Add missing display_lvname in _lvconvert_merge_thin_snapshot().

Also when we detect missing origin, report Internal error,
which would likely be the primary fault here
(and avoid dereft of NULL origin as noticed by Coverity).
2015-11-16 01:16:11 +01:00
0f4d96f1bd cleanup: just alphabetically sort links 2015-11-16 01:16:11 +01:00
dccbc3b621 cleanup: simplify dev_cache_exit
Just set whole _cache struct into unitialized state just
like with lib init start usage.
Lists are initialized with dev_cache_init().
2015-11-16 01:16:11 +01:00
5a4676fea9 cleanup: add _free on error path
Just like with failing allocation above also _free(dev).

TODO: rework this to always use mempool and drop unneeded
comlexity we have in this function.
2015-11-16 01:16:11 +01:00
c3b292a4a9 format-text: ensure no division by zero
Coverity likes here to be 100% sure no division by zero is possible.
Add check for alignment !=0 which is made on other code paths here.
2015-11-16 01:16:11 +01:00
193e7f5973 config: check vdef pointer before dereference
Coverity notices we check for v_def != NULL elsewhere, so it thinks
it may be possibly NULL also here.
2015-11-16 01:16:11 +01:00
96d73dc6ea libdm: check for passed custom time value
Coverity reports custom should be checked before derefernce.
2015-11-16 01:16:11 +01:00
d4288c9bdf libdm: check for null from pool strdup
Unlikely to happen, but Coverity shown we may have possible
derefer NULL pointer.
2015-11-16 01:16:09 +01:00
422c7474ca libdm: check if passed return pointer is not NULL
Coverity: before storing return value, check passed space will
not dereference NULL pointer.
2015-11-16 01:15:04 +01:00
dd9a05b5ae man: improve cmirrord.8 manpage
- Keywords in bold
- Add syslog and signal ref.
- Sort see also sections

Signed-off-by: Stéphane Aulery <saulery@free.fr>
2015-11-16 01:15:03 +01:00
376892ddf8 clvmd: remove -v option from getopt
-V is documented, not -v.

Signed-off-by: Stéphane Aulery <saulery@free.fr>
2015-11-16 01:15:03 +01:00
e31f4b76f4 cache: handle older metadata format
When reading older lvm2 metadata for cache-pool - we now handle more
extended syntax - basically we want to enter most setting when
actually creating cached LV.

For this new validation code has been added. However older metadata
without new settings set is now found as invalid.

Fix it by adding default settings for  cache policy  mq
and cache mode  writethrough.
2015-11-16 01:12:57 +01:00
d9295410e9 lvmetad: change the new hash to take data len
If the data len is passed into the hash table
and saved there, then the hash table internals
do not need to assume that the data value is
a string at any point.
2015-11-13 16:54:22 -06:00
e425bce281 tests: allow lvmetad tests with duplicate VG names 2015-11-13 15:09:26 -06:00
46193f4a59 lvmetad: handle duplicate VG names
New hash table functions are added that allow for
multiple entries with the same key.  Use of the
vgname_to_vgid hash table is converted to these
new functions since there are multiple entries
in vgname_to_vgid that have the same key (vgname).

When multiple VGs with the same name exist, commands
that reference only a VG name will fail saying the
VG could not be found (that error message could be
improved.)  Any command that works with the select
option can access one of the VGs with -S vg_uuid=X.
vgrename is a special case that allows the first VG
name arg to be replaced by a uuid, which also works.

(The existing hash table implementation is not well
suited for handling this case, but it works ok with
the new extensions.  Changing lvmetad to use its own
custom hash tables may be preferable at some point.)
2015-11-13 14:56:35 -06:00
970a428909 pvmove: Remove unused find_pvmove_lv_from_pvname. 2015-11-13 18:06:08 +00:00
b2e13ac552 coverity: add few internal errors
Mark impossible paths with internal errors.
Also replace 'strcmp() with more readable seg_is...()
2015-11-13 11:18:27 +01:00
3089f5ab15 coverity: model some function
Reduce number of false-positives and model functions in a way
Coverity is able to understand it.
2015-11-13 11:18:27 +01:00
8d258c7df4 coverity: hint
Here Coverity cannot see the pointer cannot be NULL in this
code path - opened coverity case #00531860.

We could make a model to avoid seeing related reports,
but then we loose coverage for modeled function.

So decided to add minor hint for this case.
2015-11-13 11:18:27 +01:00
ea1814cea8 tests: without delay_dev skip some checks
When delay_dev is missing these tests are just racy.
2015-11-13 11:17:07 +01:00
6dadebb1e4 cleanup: better error message
Use display_lvname.
2015-11-13 11:17:06 +01:00
1f2a42c7b7 cleanup: check LVs in one statement
Use a single statement to check all LVs we want to
deref via  get_only_segment_using_this_lv().
2015-11-13 11:17:06 +01:00
70af08122e cleanup: missing check for PV2
Patch missed also check this pointer dereference.
2015-11-13 11:17:06 +01:00
e0828e885b cleanup: drop unneded check for mem
Revert missed to drop this extra check.
2015-11-13 11:17:06 +01:00
112c0592ad debug: put stack on error path
At least check result and trace it.
However we may need better error reaction in this case.
2015-11-13 11:17:06 +01:00
007be91e3d raid: ensure area_count is at least 2
Enusure we will not divide by 0.
2015-11-13 11:17:06 +01:00
d74e1291cd libdm: put in secure check
Coverity complains about NULL deref - while this cannot currently
happen, put in secure INTERNAL_ERROR.
2015-11-13 11:17:05 +01:00
0128770d6d reporter: add missing stack trace
Use goto_out on error paths.
2015-11-13 11:17:05 +01:00
43777b551d lvmetad: tail chasing to shut up coverity 2015-11-12 09:35:41 -06:00
058725c721 dmeventd: fix check for failing open.
Recent change 2c8d6f5c90
actually droped restart when the reason of failing open is missing
device completely - check for ENOENT now as another reason
to start new dmeventd server  (when there is no systemd to maintain it).
2015-11-11 19:54:55 +01:00
1e729c47d2 str_list: do not support str lists without mempools
Do not support str lists without mempools. Instead, create temporary
mempool where necessary (currently only _get_report_options fn).
2015-11-11 16:09:52 +01:00
b8779e706e configure: check for udev_device_get_is_initialized is available
The udev_device_get_is_initialized is available since libudev version
165. Older versions are still used somewhere (e.g. RHEL6). So better
check for this fn and use it only if it's available.
2015-11-11 15:15:50 +01:00
f82e0210b7 dev-ext: issue error if external_device_info_source=udev and udev db record incomplete
Udev db records are marked as not initialized (incomplete) on timeout.
Issue an error message whenever LVM finds such records so users are
aware that something's going wrong with udev db.

This is important in case we use devices/external_device_info_source="udev"
where udev database records are used to do various filtering decisions.

For example:

udev log of timed out worker:

Nov 11 13:02:25 raw.virt systemd-udevd[607]: seq 1997 '/devices/virtual/block/dm-2' is taking a long time
Nov 11 13:04:25 raw.virt systemd-udevd[607]: seq 1997 '/devices/virtual/block/dm-2' killed
Nov 11 13:04:25 raw.virt systemd-udevd[607]: worker [11221] terminated by signal 9 (Killed)
Nov 11 13:04:25 raw.virt systemd-udevd[607]: worker [11221] failed while handling '/devices/virtual/block/dm-2'
...

LVM also issues error message visibly if incomplete udev db record is found,
devices/external_device_info_source="udev" is set:

$ pvs
  Udev database has incomplete information about device /dev/dm-2.
  Failed to get external handle for device /dev/dm-2 [udev].
  ...
2015-11-11 13:14:07 +01:00
6d0db97163 libdm: reorder error path
Coverity noticed recent fix of an error path missed to
release 'dmt' - reoder code to ensure 'dmt' is released.
2015-11-10 21:41:47 +01:00
a45cc0fe14 raid: fix the string compare
Coverity noticed this condition is always false and the error
path could never be visited.

So check for all mismatches of supported messages
and actually mark log_error as internal error.
2015-11-10 21:40:28 +01:00
59905100d1 coverity: Add placeholder modelling file. 2015-11-10 01:37:11 +00:00
fb59847a0f libdm: replace assign with increment
Coverity didn't liked assign with && expression, so use trick.
It does not complain against this prefix incremenent operation.
2015-11-09 22:51:48 +01:00
7ec61cd5b9 vgrename: check if new and old names match
When the first arg is a UUID and vgrename translates
that UUID to a current VG name, the old and new VG
names are not being checked for equality.  If they
are equal, it produces an internal error rather than
a proper error.
2015-11-09 13:23:59 -06:00
cd937efa77 lvmetad: change recent cleanups
with better alternatives.
2015-11-09 12:18:43 -06:00
d2d5191b78 lvmlockd: reverse some unnecessary checking
These are unnecessary or not useful.
2015-11-09 12:18:43 -06:00
a0cb92cbb1 tests: handle missing delay_dev
Try to run as much of test which could run without delay_dev.
2015-11-09 19:07:53 +01:00
6762eec88c lvmlockd: fix the NO_GL_LS condition
indicating when no global lockspace exists.
2015-11-09 11:33:16 -06:00
45e749493c cleanup: ensuring string is not NULL
Coverity cannot see the string cannot be NULL so make it explicit.
2015-11-09 17:04:10 +01:00
76b42901c0 cache: ensure there is no NULL str
Coverity is not smart enough to detect this case could never happen.
2015-11-09 17:04:10 +01:00
b1215b7f8c lvmlockd: enforce 64bit arithmetic
Coverity suggest to stay on the 'safe' side and widen operators early
so 64bit offset is made from 64bit arithmentic.
2015-11-09 17:04:10 +01:00
d6767d753f lvmlockd: add missing error checks
Detect error from function and report them.
2015-11-09 17:04:10 +01:00
c2d5cfbdb8 cleanup: use _ for local function 2015-11-09 17:04:10 +01:00
3db5ba08b1 cleanup: drop unneded headers
Coverity notices they are not really needed.
2015-11-09 17:04:10 +01:00
6c331f3061 dmsetup: one missed dms 2015-11-09 17:04:10 +01:00
32762e2a9c libdaemon: fix passing 32bit values for %d
Since %d is now prohibited for its great confusion,
replace it with  FMTd64 and correctly converted int64_t
parameter.
2015-11-09 17:04:10 +01:00
e207ededd6 lvmlockd: shut up warnings 2015-11-09 10:00:04 -06:00
36ee367343 libdaemon: prohibit use of %d for 64bit numbres
Do not let pass %d and print internal error when found one.
Require all users to use  FMTd64 - it's seriously confusing.
2015-11-09 14:03:25 +01:00
0b5a75c9af lvmetad: restore use of FMTd64
daemon_reply_simple() eats just 64bit numbers - so make it explicit.
2015-11-09 14:02:27 +01:00
7103012754 tests: update test to check for race better
Use  delay_dev to slow down mirror sync so we could more
easily check for race and proper reject of parallel mirror
leg addition/reduction.

Also expose fail in mirror allocation of parallel leg.
2015-11-09 12:21:17 +01:00
ab4773671b tests: do not skip test when delay is missing
Rather then skipping whole test - just do not use it.

Failing tests that have required delay need to deal with reality
and shell either check for HAVE_DM_DELAY and skip portion
of test or using should when needed.
2015-11-09 12:21:17 +01:00
e4c9b390ca cleanup: update comment 2015-11-09 12:21:17 +01:00
84a9546869 dmsetup: cleanup warn for older compilers
Older gcc somehow thinks there is a path of using
subcommand uninitilized.

So make it more obvious there is no such one.
2015-11-09 12:21:17 +01:00
5aae8de776 lvmetad: maintain seqno as int
Keep seqno as 32bit value.
Also use '_' prefix for local _update_metadata.
2015-11-09 12:21:17 +01:00
57c2a1ae8c raid: mark intententional copy and paste
Coverity: add this extra comment, to let Coverity know this
slightly changed copy&paste code is intentional.
2015-11-09 10:22:52 +01:00
846adadbcc cleanup: use code in place
Pass const strings to printf(),
and use  struct names directly instead of creating unused vars on stack.
2015-11-09 10:22:52 +01:00
22e19cb354 cleanup: reoder rstatus init
In all error paths always initialize *rstatus.
2015-11-09 10:22:52 +01:00
b1dab26be0 cleanup: coverity quiet
While through all codepaths we never 'read' lock_id unless LCKF_CONVERT,
coverity cannot decrypt this.

As since it's usually better to pass in 'well-defined' data structures
preset lock_id to 0.
2015-11-09 10:22:52 +01:00
11151121aa cleanup: use fputs for plain strings
Use fputs() when printing plain string,
easier then fprintf which needs to parse it.

Also check fd before close is >= 0 -
it is - but coverity fail to see it, so eliminate
this false-positive warning.
2015-11-09 10:22:52 +01:00
c4c5635870 cleanup: drop unneeded assign
prio is always assigned later.
2015-11-09 10:22:52 +01:00
e262d5e596 cleanup: keep using enum typedef
Using enum instead of unsigned.
2015-11-09 10:22:52 +01:00
9b9b5d0ea2 cleanup: use 64bit multiply for print 2015-11-09 10:22:52 +01:00
f6d2528f64 cleanup: drop unneeded header file 2015-11-09 10:22:51 +01:00
5ba219e87a cleanup: use display_lvname 2015-11-09 10:22:51 +01:00
04f76d9020 cleanup: use NAME_LEN
Let's have instant check for max name len when creating
subLV name.
2015-11-09 10:22:51 +01:00
5c48ef993b cleanup: use NAME_LEN buffer instead of alloca
Drop alloca and use NAME_LEN size to get implicit check
for max len of LV name.
2015-11-09 10:22:51 +01:00
2e04eee192 cleanup: do not test alloca for NULL
alloca() never returns NULL.
In case stack is out-of-range the behaviour is undefined.
2015-11-09 10:22:51 +01:00
c542c18d2a cleanup: drop unneded assign
Coverity doesn't really like to see subcommand being assigned NULL,
so drop it.
2015-11-09 10:22:51 +01:00
07046e994f alloc: use own mem pool for alloc_handle
Keep alloc_handle's data in a single mempool and do not
spread them into vgmem pool.
2015-11-09 10:22:49 +01:00
0c380c316c cleanup: relocate error capture
Capture internal error before allocation anything.
2015-11-09 10:21:09 +01:00
67b4761bc3 toollib: add missing check for lvmcache_init()
Coverity notices lvmcache_init() may fail so check and
error out in case of failure.
2015-11-09 10:19:20 +01:00
164d7e72bf devmanager: validate target params
Coverity: ensure we do not read through NULL pointers for
target_type and params.
2015-11-09 10:19:20 +01:00
4f8f8fcb52 report: add extra pointer check
Coverity was seeing possible trouble with NULL pointer dereference.
So ensure it may never happen.
2015-11-09 10:19:20 +01:00
856e11e11c lv_manip: do not deref NULL for debug message
Coverity: when 'pv2' would be passed as NULL, do not try to
deref it in debug message.
2015-11-09 10:19:20 +01:00
fa1d730847 dev-type: fix TOCTOU order
Doing 'stat' checking first and later opening is racy.
And since we do not really care about any 'status' info
here and we read 'sysfs' here - just drop whole 'stat()'
call and directly handle error from failing 'fopen()'.
2015-11-09 10:19:20 +01:00
80c3fb786c thin: fix error path mem leak
Coverity: when parsing of thin-pool status would have failed,
it could have leaked memory pool and dmt struct.
2015-11-09 10:19:19 +01:00
3cadc1c87e libdm: add test for dm_task_get_message_response()
Coverity notices dm_task_get_message_response() result should be
checked for NULL which should not be passed to dm_pool_strdup().
2015-11-09 10:19:19 +01:00
84303dc17a libdm: exlicitly check for NULL
Coverity: another explict check for NULL, where coverity fails to
see it.
2015-11-09 10:19:19 +01:00
f6c140e200 libdm: ensure vars are initialized
Coverity found potential error path, where code could
have used some unset variables.
2015-11-09 10:19:19 +01:00
b1c4017743 libdm: add missing error path check
Coverity: do not continue with section cloning when root node
would a NULL.
2015-11-09 10:19:19 +01:00
18fd0bd20c lvconvert: add extra check for existance of pointer
Coverity here is not fully-in-picture - but please it
with validation of pointer which currently cannot be null,
since we always return at least empty string.
2015-11-09 10:19:19 +01:00
b83a20b80a lvmetad: validate mda is not NULL
Coverity: make it explicitely obvious metadata area is not NULL.
2015-11-09 10:19:19 +01:00
99def8f439 lvmetad: check for pointers not NULL
Check for  arg_vgid_lookup and arg_name_lookup not being NULL.
Drop checking arg_vgid and arg_name for NULL since they
are already dereference earlier - thus mostly must be NOT NULL.

(If that would be possible larger rework of this function would be
required).
2015-11-09 10:19:19 +01:00
f66fe2c444 lvmetad: require meta_lookup
Coverity: do not call update_pvid_to_vgid() with
meta_lookup == NULL since it is dereferencing it.
2015-11-09 10:19:19 +01:00
91bde0f4a1 lvmetad: check for allocation fail
Coverity: missing check for root != NULL as this pointer is
later dereferenced in add_last_node().
2015-11-09 10:19:19 +01:00
297d6773af dmsetup: add missing checks for dm_stats_create() ret value
Coverity likes to see a check for dms not being NULL, so
add those missing ones...
2015-11-09 10:19:19 +01:00
e90c5d2060 dmsetup: check for NULL from dm_task_get_ioctl_timestamp
Coverity: ensure NULL is not passed to dm_timestamp_delta().
2015-11-09 10:19:19 +01:00
9df3069083 clvmd: check for pthread_create status
Coverity: likes to see checked function result.
2015-11-09 10:19:18 +01:00
2c8d6f5c90 dmeventd: open fifo in one function
Put calls related to fifo opening into a single function.

Fix  Time-Of-Check-Time-Of-Use and use fstat()
and fchmod() on already opened fd instead of
checking first path and then risking to open something
different.
2015-11-09 10:18:53 +01:00
e1b111b02a dmeventd: reorder tou 2015-11-09 10:00:33 +01:00
8b857bfdc6 libdevmapper-event: fix fifo leak on error path
Coverity: when _init_client() fails, client fifo could have
been already openned and needs to be closed on error path.
2015-11-09 10:00:13 +01:00
459b3db61e configure: report whether to build lvmlockd
Report configured status for build with lvmlockd.
2015-11-09 09:58:27 +01:00
af6adec7cc post-release 2015-11-09 01:48:57 +00:00
a3f77ed4ba pre-release 2015-11-09 01:45:22 +00:00
b9341e36f1 test: disable duplicate VG name test for lvmetad
Until we decide how duplicate VG names should be
handled by lvmetad, and implement that.
2015-11-06 15:58:22 -06:00
8096f2224c mirror: Fix log size calc when more than 1 extent.
Currently the code creates the log separately after allocating space for
the data and as no data allocation is needed this second time,
total_extents ends up holding zero so use new_extents directly instead.
2015-11-05 23:40:47 +00:00
16780f6faa vg_read: skip repair and wipe for foreign and shared VGs
When reading a foreign VG we cannot write it, since
it belongs to another host.  When reading a shared VG
we cannot write it because we may not have an ex lock.
(Or we may be reading the shared VG while not using
lvmlockd in which case it's like reading a foreign VG.)

Add the same checks for wiping outdated PVs.  We may
read a foreign or shared VG, or see the PVs, while
another host is part way through writing a new version
of the VG to the PVs.  This might cause us to think
some of the PVs are outdated.  We do not want to
write another host's PVs, especially when we may
wrongly conclude they are outdated.
2015-11-03 13:42:21 -06:00
4103896ca0 lvmcache: change log_verbose to log_warn
Without this, some cases miss printing a
warning for duplicate PVs.
2015-11-03 13:37:31 -06:00
d30105f471 lvmetad: log duplicate PVs returned from lvmetad
When the command gets a list of alternate devices
from lvmetad, log each one directly.  This is not
the same as the warnings when adding lvmcache,
which are related to which duplicate is preferred.
2015-11-03 13:35:51 -06:00
19feda2c95 tests: skip duplicate vg names test with lvmetad
If two PVs have different VGs with the same name
(different uuids), one of the VGs is ignored by
lvmetad.  A FIXME exists in lvmetad to find a
better response.
2015-11-03 13:25:35 -06:00
4e6377f5ba lvmetad: refactor and document
update_metadata and pv_found update the cached metadata;
these are both reworked to improve the code, organize it
by each possible state and transition, make it much more
clear what's changing, add more error checking and
handling, and add comments.

The state and content of the cache (hash tables) does not
change (apart from some things that didn't work before),
and the communication to/from commands does not change.
The implementation and organization of the code making
the state changes does change significantly.

One detail related to the content of the cache does change:
different hash tables do not reference the same memory any more;
the target values in each hash table are allocated and freed
individually.
2015-11-03 13:18:27 -06:00
4b47ee5296 config: fix copy error in examples
The same example was copied without
changing the variable name.
2015-11-03 11:07:27 -06:00
769 changed files with 20211 additions and 5212 deletions

2
.gitignore vendored
View File

@ -7,6 +7,8 @@
*.orig
*.pc
*.pot
*.pyc
*.pyo
*.rej
*.so
*.so.*

View File

@ -2,7 +2,7 @@
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@ -305,7 +305,7 @@ the "copyright" line and a pointer to where the full notice is found.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.

View File

@ -10,7 +10,7 @@
#
# 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
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@
@ -95,7 +95,7 @@ endif
DISTCLEAN_TARGETS += cscope.out
CLEAN_DIRS += autom4te.cache
check check_system check_cluster check_local check_lvmetad check_lvmpolld unit: all
check check_system check_cluster check_local check_lvmetad check_lvmpolld check_lvmlockd_test check_lvmlockd_dlm check_lvmlockd_sanlock unit: all
$(MAKE) -C test $(@)
conf.generate: tools
@ -166,8 +166,11 @@ install_tmpfiles_configuration:
LCOV_TRACES = libdm.info lib.info liblvm.info tools.info \
libdaemon/client.info libdaemon/server.info \
daemons/clvmd.info daemons/dmeventd.info \
daemons/lvmetad.info
daemons/clvmd.info \
daemons/dmeventd.info \
daemons/lvmetad.info \
daemons/lvmlockd.info \
daemons/lvmpolld.info
CLEAN_TARGETS += $(LCOV_TRACES)

View File

@ -1 +1 @@
2.02.134(2)-git (2015-10-30)
2.02.144(2)-git (2016-02-26)

View File

@ -1 +1 @@
1.02.111-git (2015-10-30)
1.02.118-git (2016-02-26)

123
WHATS_NEW
View File

@ -1,5 +1,126 @@
Version 2.02.134 -
Version 2.02.144 - 26th February 2016
=====================================
Only show (u)sed pv_attr char when PV is not (a)llocatable. (2.02.143)
Update makefile to generate lcov output also for lvmpolld and lvmlockd.
Fix SystemdService lvm2-lvmdbusd.service name.
Improve support for env LVM_VG_NAME for reference VG name in lvconvert.
Fix regression when lvresize accepted zero sizes. (2.02.141)
Always warn user about PV in use even when pvremove uses --force --force.
Use uninitialized pool header detection in all cases.
Fix read error detection when checking for uninitialized thin-pool header.
Fix error path for internal error in lvmetad VG lookup code.
Version 2.02.143 - 21st February 2016
=====================================
Fix error path when sending thin-pool message fails in update_pool_lv().
Support reporting CheckNeeded and Fail state for thin-pool and thin LV.
For failing thin-pool and thin volume correctly report percentage as INVALID.
Report -1, not 'unkown' for lv_{snapshot_invalid,merge_failed} with --binary.
Add configure --enable-dbus-service for an LVM D-Bus service.
Replace configure --enable-python_bindings with python2 and python3 versions.
If PV belongs to some VG and metadata missing, skip it if system ID is used.
Automatically change PV header extension to latest version if writing PV/VG.
Identify used PVs in pv_attr field by new 'u' character.
Add pv_in_use reporting field to report if PV is used or not.
Add pv_ext_vsn reporting field to report PV header extension version.
Add protective flag marking PVs as used even if no metadata available.
Version 2.02.142 - 15th February 2016
=====================================
Fix memory pool corruption in pvmove (2.02.141).
Support control of spare metadata creation when repairing thin-pool.
Fix config type of 'log/verbose' from bool to int (2.02.99).
Fix inverted data LV thinp watermark calc for dmeventd response (2.02.133).
Use use_blkid_wiping=0 if not defined in lvm.conf and support not compiled in.
Do not check for suspended devices if scanning for lvmetad update.
Clear cached bootloader areas when PV format changed.
Fix partn table filter with external_device_info_source="udev" and blkid<2.20.
Version 2.02.141 - 25th January 2016
====================================
Add metadata/check_pv_device_sizes switch to lvm.conf for device size checks.
Warn if device size is less than corresponding PV size in metadata.
Cache device sizes internally.
Restore support for command breaking in process_each_lv_in_vg() (2.02.118).
Use correct mempool when process_each_lv_in_vg() (2.02.118).
Fix lvm.8 man to show again prohibited suffixes.
Fix configure to set proper use_blkid_wiping if autodetected as disabled.
Initialise udev in clvmd for use in device scanning. (2.02.116)
Add seg_le_ranges report field for common format when displaying seg devices.
Honour report/list_item_separator for seg_metadata_le_ranges report field.
Don't mark hidden devs in -o devices,metadata_devices,seg_pe_ranges.(2.02.140)
Change LV sizes in seg_pe_ranges report field to match underlying devices.
Add kernel_cache_settings report field for cache LV settings used in kernel.
Version 2.02.140 - 16th January 2016
====================================
Fix lvm2app to return either 0 or 1 for lvm_vg_is_{clustered,exported}.
Add kernel_discards report field to display thin pool discard used in kernel.
Correct checking of target presence when driver access is disabled.
Eval poolmetadatasize arg earlier in lvresize.
Fix vgcfgrestore to respect allocatable attribute of PVs.
Add report/mark_hidden_devices to lvm.conf.
Use brackets consistently in report fields to mark hidden devices.
Restore background polling processing during auto-activation (2.02.119).
Fix invalid memory read when reporting cache LV policy_name (2.02.126).
Version 2.02.139 - 8th January 2016
===================================
Update lvmlockd with the new VG seqno before devices are suspended.
Rework vgrename to use the common processing code in toollib.
Make pvs show new devices on the system since the last .cache update.
Document F,D and M thin pool health status chars for lv_attr in lvs man page.
Also add lvm2-activation{-early,-net}.service systemd status for lvmdump -s.
Version 2.02.138 - 14th December 2015
=====================================
Support lvrename for hidden (used) cache pools.
Fix lvrename for stacked cache pools.
Version 2.02.137 - 5th December 2015
====================================
Restore archiving before changing metadata in vgextend (2.02.117).
Dropped internal usage of log_suppress(2).
Cleaned logging code for buffer size usage.
Added internal id_read_format_try() function to check and read valid UUID.
Change lvcreate, lvrename, lvresize to use process_each_vg.
Change process_each_vg to handle single VG as separate arg.
Issue error if ambiguous VG name is supplied in most commands.
Make process_each fns always work through full list of known VG names.
Use dm_get_status_mirror() instead of individual parsers.
Add mem pool arg for check_transient_status() target function.
Avoid misleading error with -m is omitted with lvconvert to raid types.
Add system_id to vginfo cache.
Version 2.02.136 - 28th November 2015
=====================================
Add new --sinceversion option for lvmconfig --type new.
Fix inactive table loaded for wrapping thin-pool when resizing it.
Extend the list of ignored libraries when locking memory.
Version 2.02.135 - 23rd November 2015
=====================================
Add a model file for Coverity.
Show correct error message for unsupported yet cache pool repair.
Allow lvconvert cache pools' data and metadata LV to raid.
Fix reading of old metadata with missing cache policy or mode settings.
Issue error if external_device_info_source=udev and udev db record incomplete.
Update lvmetad duplicate VG name handling to use hash function extensions.
Detect invalid vgrenames by vgid where the name is unchanged.
Fix passing of 32bit values through daemons (mostly lvmlockd).
Use local memory pool for whole alloc_handle manipulation.
Add missing pointer validation after dm_get_next_target().
Do not deref NULL pointer in debug message for _match_pv_tags().
Drop unneeded stat() call when checking for sysfs file.
Fix memory leak on error path of failing thin-pool percentage check.
Add missing test for failing node allocation in lvmetad.
Correct configure messages when enabling/disabling lvmlockd.
Version 2.02.134 - 9th November 2015
====================================
Refactor some lvmetad code and adjust some duplicate PV messages.
No longer repair/wipe VG/PVs if inaccessible because foreign or shared.
Pass correct data size to mirror log calc so log can be bigger than 1 extent.
Version 2.02.133 - 30th October 2015
====================================

View File

@ -1,5 +1,44 @@
Version 1.02.111 -
Version 1.02.118 - 26th February 2016
=====================================
Fix string boundary check in _get_canonical_field_name().
Always initialized hist struct in _stats_parse_histogram().
Version 1.02.117 - 21st February 2016
=====================================
Improve status parsing for thin-pool and thin devices.
Version 1.02.116 - 15th February 2016
=====================================
Use fully aligned allocations for dm_pool_strdup/strndup() (1.02.64).
Fix thin-pool table parameter feature order to match kernel output.
Version 1.02.115 - 25th January 2016
====================================
Fix man page for dmsetup udevcreatecookie.
Version 1.02.114 - 14th December 2015
=====================================
Better support for dmsetup static linkage.
Extend validity checks on dmeventd client socket.
Version 1.02.113 - 5th December 2015
====================================
Mirror plugin in dmeventd uses dm_get_status_mirror().
Add dm_get_status_mirror() for parsing mirror status line.
Version 1.02.112 - 28th November 2015
=====================================
Show error message when trying to create unsupported raid type.
Improve preloading sequence of an active thin-pool target.
Drop extra space from cache target line to fix unneded table reloads.
Version 1.02.111 - 23rd November 2015
=====================================
Extend dm_hash to support multiple values with the same key.
Add missing check for allocation inside dm_split_lvm_name().
Test dm_task_get_message_response for !NULL in dm_stats_print_region().
Add checks for failing dm_stats_create() in dmsetup.
Add missing fifo close when failed to initialize client connection.
Version 1.02.110 - 30th October 2015
====================================

311
aclocal.m4 vendored
View File

@ -12,10 +12,67 @@
# PARTICULAR PURPOSE.
m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_python_module.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_PYTHON_MODULE(modname[, fatal, python])
#
# DESCRIPTION
#
# Checks for Python module.
#
# If fatal is non-empty then absence of a module will trigger an error.
# The third parameter can either be "python" for Python 2 or "python3" for
# Python 3; defaults to Python 3.
#
# LICENSE
#
# Copyright (c) 2008 Andrew Collier
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 8
AU_ALIAS([AC_PYTHON_MODULE], [AX_PYTHON_MODULE])
AC_DEFUN([AX_PYTHON_MODULE],[
if test -z $PYTHON;
then
if test -z "$3";
then
PYTHON="python3"
else
PYTHON="$3"
fi
fi
PYTHON_NAME=`basename $PYTHON`
AC_MSG_CHECKING($PYTHON_NAME module: $1)
$PYTHON -c "import $1" 2>/dev/null
if test $? -eq 0;
then
AC_MSG_RESULT(yes)
eval AS_TR_CPP(HAVE_PYMOD_$1)=yes
else
AC_MSG_RESULT(no)
eval AS_TR_CPP(HAVE_PYMOD_$1)=no
#
if test -n "$2"
then
AC_MSG_ERROR(failed to find required module $1)
exit 1
fi
fi
])
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
# serial 1 (pkg-config-0.24)
#
# Copyright (c) 2004 Scott James Remnant <scott@netsplit.com>.
# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -227,4 +284,256 @@ AS_VAR_COPY([$1], [pkg_cv_][$1])
AS_VAR_IF([$1], [""], [$5], [$4])dnl
])# PKG_CHECK_VAR
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# AM_PATH_PYTHON([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
# ---------------------------------------------------------------------------
# Adds support for distributing Python modules and packages. To
# install modules, copy them to $(pythondir), using the python_PYTHON
# automake variable. To install a package with the same name as the
# automake package, install to $(pkgpythondir), or use the
# pkgpython_PYTHON automake variable.
#
# The variables $(pyexecdir) and $(pkgpyexecdir) are provided as
# locations to install python extension modules (shared libraries).
# Another macro is required to find the appropriate flags to compile
# extension modules.
#
# If your package is configured with a different prefix to python,
# users will have to add the install directory to the PYTHONPATH
# environment variable, or create a .pth file (see the python
# documentation for details).
#
# If the MINIMUM-VERSION argument is passed, AM_PATH_PYTHON will
# cause an error if the version of python installed on the system
# doesn't meet the requirement. MINIMUM-VERSION should consist of
# numbers and dots only.
AC_DEFUN([AM_PATH_PYTHON],
[
dnl Find a Python interpreter. Python versions prior to 2.0 are not
dnl supported. (2.0 was released on October 16, 2000).
m4_define_default([_AM_PYTHON_INTERPRETER_LIST],
[python python2 python3 python3.3 python3.2 python3.1 python3.0 python2.7 dnl
python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0])
AC_ARG_VAR([PYTHON], [the Python interpreter])
m4_if([$1],[],[
dnl No version check is needed.
# Find any Python interpreter.
if test -z "$PYTHON"; then
AC_PATH_PROGS([PYTHON], _AM_PYTHON_INTERPRETER_LIST, :)
fi
am_display_PYTHON=python
], [
dnl A version check is needed.
if test -n "$PYTHON"; then
# If the user set $PYTHON, use it and don't search something else.
AC_MSG_CHECKING([whether $PYTHON version is >= $1])
AM_PYTHON_CHECK_VERSION([$PYTHON], [$1],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])
AC_MSG_ERROR([Python interpreter is too old])])
am_display_PYTHON=$PYTHON
else
# Otherwise, try each interpreter until we find one that satisfies
# VERSION.
AC_CACHE_CHECK([for a Python interpreter with version >= $1],
[am_cv_pathless_PYTHON],[
for am_cv_pathless_PYTHON in _AM_PYTHON_INTERPRETER_LIST none; do
test "$am_cv_pathless_PYTHON" = none && break
AM_PYTHON_CHECK_VERSION([$am_cv_pathless_PYTHON], [$1], [break])
done])
# Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON.
if test "$am_cv_pathless_PYTHON" = none; then
PYTHON=:
else
AC_PATH_PROG([PYTHON], [$am_cv_pathless_PYTHON])
fi
am_display_PYTHON=$am_cv_pathless_PYTHON
fi
])
if test "$PYTHON" = :; then
dnl Run any user-specified action, or abort.
m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])])
else
dnl Query Python for its version number. Getting [:3] seems to be
dnl the best way to do this; it's what "site.py" does in the standard
dnl library.
AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version],
[am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[[:3]])"`])
AC_SUBST([PYTHON_VERSION], [$am_cv_python_version])
dnl Use the values of $prefix and $exec_prefix for the corresponding
dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX. These are made
dnl distinct variables so they can be overridden if need be. However,
dnl general consensus is that you shouldn't need this ability.
AC_SUBST([PYTHON_PREFIX], ['${prefix}'])
AC_SUBST([PYTHON_EXEC_PREFIX], ['${exec_prefix}'])
dnl At times (like when building shared libraries) you may want
dnl to know which OS platform Python thinks this is.
AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform],
[am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`])
AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform])
# Just factor out some code duplication.
am_python_setup_sysconfig="\
import sys
# Prefer sysconfig over distutils.sysconfig, for better compatibility
# with python 3.x. See automake bug#10227.
try:
import sysconfig
except ImportError:
can_use_sysconfig = 0
else:
can_use_sysconfig = 1
# Can't use sysconfig in CPython 2.7, since it's broken in virtualenvs:
# <https://github.com/pypa/virtualenv/issues/118>
try:
from platform import python_implementation
if python_implementation() == 'CPython' and sys.version[[:3]] == '2.7':
can_use_sysconfig = 0
except ImportError:
pass"
dnl Set up 4 directories:
dnl pythondir -- where to install python scripts. This is the
dnl site-packages directory, not the python standard library
dnl directory like in previous automake betas. This behavior
dnl is more consistent with lispdir.m4 for example.
dnl Query distutils for this directory.
AC_CACHE_CHECK([for $am_display_PYTHON script directory],
[am_cv_python_pythondir],
[if test "x$prefix" = xNONE
then
am_py_prefix=$ac_default_prefix
else
am_py_prefix=$prefix
fi
am_cv_python_pythondir=`$PYTHON -c "
$am_python_setup_sysconfig
if can_use_sysconfig:
sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'})
else:
from distutils import sysconfig
sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix')
sys.stdout.write(sitedir)"`
case $am_cv_python_pythondir in
$am_py_prefix*)
am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'`
am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"`
;;
*)
case $am_py_prefix in
/usr|/System*) ;;
*)
am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages
;;
esac
;;
esac
])
AC_SUBST([pythondir], [$am_cv_python_pythondir])
dnl pkgpythondir -- $PACKAGE directory under pythondir. Was
dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is
dnl more consistent with the rest of automake.
AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE])
dnl pyexecdir -- directory for installing python extension modules
dnl (shared libraries)
dnl Query distutils for this directory.
AC_CACHE_CHECK([for $am_display_PYTHON extension module directory],
[am_cv_python_pyexecdir],
[if test "x$exec_prefix" = xNONE
then
am_py_exec_prefix=$am_py_prefix
else
am_py_exec_prefix=$exec_prefix
fi
am_cv_python_pyexecdir=`$PYTHON -c "
$am_python_setup_sysconfig
if can_use_sysconfig:
sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_prefix'})
else:
from distutils import sysconfig
sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_prefix')
sys.stdout.write(sitedir)"`
case $am_cv_python_pyexecdir in
$am_py_exec_prefix*)
am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'`
am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"`
;;
*)
case $am_py_exec_prefix in
/usr|/System*) ;;
*)
am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages
;;
esac
;;
esac
])
AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir])
dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE)
AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE])
dnl Run any user-specified action.
$2
fi
])
# AM_PYTHON_CHECK_VERSION(PROG, VERSION, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
# ---------------------------------------------------------------------------
# Run ACTION-IF-TRUE if the Python interpreter PROG has version >= VERSION.
# Run ACTION-IF-FALSE otherwise.
# This test uses sys.hexversion instead of the string equivalent (first
# word of sys.version), in order to cope with versions such as 2.2c1.
# This supports Python 2.0 or higher. (2.0 was released on October 16, 2000).
AC_DEFUN([AM_PYTHON_CHECK_VERSION],
[prog="import sys
# split strings by '.' and convert to numeric. Append some zeros
# because we need at least 4 digits for the hex conversion.
# map returns an iterator in Python 3.0 and a list in 2.x
minver = list(map(int, '$2'.split('.'))) + [[0, 0, 0]]
minverhex = 0
# xrange is not present in Python 3.0 and range returns an iterator
for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]]
sys.exit(sys.hexversion < minverhex)"
AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])])
# Copyright (C) 2001-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# AM_RUN_LOG(COMMAND)
# -------------------
# Run COMMAND, save the exit status in ac_status, and log it.
# (This has been adapted from Autoconf's _AC_RUN_LOG macro.)
AC_DEFUN([AM_RUN_LOG],
[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD
($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
(exit $ac_status); }])
m4_include([acinclude.m4])

170
autoconf/py-compile Executable file
View File

@ -0,0 +1,170 @@
#!/bin/sh
# py-compile - Compile a Python program
scriptversion=2011-06-08.12; # UTC
# Copyright (C) 2000-2014 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
if [ -z "$PYTHON" ]; then
PYTHON=python
fi
me=py-compile
usage_error ()
{
echo "$me: $*" >&2
echo "Try '$me --help' for more information." >&2
exit 1
}
basedir=
destdir=
while test $# -ne 0; do
case "$1" in
--basedir)
if test $# -lt 2; then
usage_error "option '--basedir' requires an argument"
else
basedir=$2
fi
shift
;;
--destdir)
if test $# -lt 2; then
usage_error "option '--destdir' requires an argument"
else
destdir=$2
fi
shift
;;
-h|--help)
cat <<\EOF
Usage: py-compile [--help] [--version] [--basedir DIR] [--destdir DIR] FILES..."
Byte compile some python scripts FILES. Use --destdir to specify any
leading directory path to the FILES that you don't want to include in the
byte compiled file. Specify --basedir for any additional path information you
do want to be shown in the byte compiled file.
Example:
py-compile --destdir /tmp/pkg-root --basedir /usr/share/test test.py test2.py
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v|--version)
echo "$me $scriptversion"
exit $?
;;
--)
shift
break
;;
-*)
usage_error "unrecognized option '$1'"
;;
*)
break
;;
esac
shift
done
files=$*
if test -z "$files"; then
usage_error "no files given"
fi
# if basedir was given, then it should be prepended to filenames before
# byte compilation.
if [ -z "$basedir" ]; then
pathtrans="path = file"
else
pathtrans="path = os.path.join('$basedir', file)"
fi
# if destdir was given, then it needs to be prepended to the filename to
# byte compile but not go into the compiled file.
if [ -z "$destdir" ]; then
filetrans="filepath = path"
else
filetrans="filepath = os.path.normpath('$destdir' + os.sep + path)"
fi
$PYTHON -c "
import sys, os, py_compile, imp
files = '''$files'''
sys.stdout.write('Byte-compiling python modules...\n')
for file in files.split():
$pathtrans
$filetrans
if not os.path.exists(filepath) or not (len(filepath) >= 3
and filepath[-3:] == '.py'):
continue
sys.stdout.write(file)
sys.stdout.flush()
if hasattr(imp, 'get_tag'):
py_compile.compile(filepath, imp.cache_from_source(filepath), path)
else:
py_compile.compile(filepath, filepath + 'c', path)
sys.stdout.write('\n')" || exit $?
# this will fail for python < 1.5, but that doesn't matter ...
$PYTHON -O -c "
import sys, os, py_compile, imp
# pypy does not use .pyo optimization
if hasattr(sys, 'pypy_translation_info'):
sys.exit(0)
files = '''$files'''
sys.stdout.write('Byte-compiling python modules (optimized versions) ...\n')
for file in files.split():
$pathtrans
$filetrans
if not os.path.exists(filepath) or not (len(filepath) >= 3
and filepath[-3:] == '.py'):
continue
sys.stdout.write(file)
sys.stdout.flush()
if hasattr(imp, 'get_tag'):
py_compile.compile(filepath, imp.cache_from_source(filepath, False), path)
else:
py_compile.compile(filepath, filepath + 'o', path)
sys.stdout.write('\n')" 2>/dev/null || :
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

View File

@ -9,7 +9,7 @@
#
# 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
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@

View File

@ -11,14 +11,22 @@
# Refer to 'man lvm.conf' for further information about profiles and
# general configuration file layout.
#
allocation {
cache_mode="writethrough"
cache_settings {
}
}
global {
units="h"
si_unit_consistency=1
suffix=1
lvdisplay_shows_full_device_path=0
}
report {
compact_output=0
compact_output_cols=""
aligned=1
buffered=1
headings=1
@ -28,6 +36,7 @@ report {
quoted=1
colums_as_rows=0
binary_values_as_numeric=0
time_format="%Y-%m-%d %T %z"
devtypes_sort="devtype_name"
devtypes_cols="devtype_name,devtype_max_partitions,devtype_description"
devtypes_cols_verbose="devtype_name,devtype_max_partitions,devtype_description"
@ -46,4 +55,5 @@ report {
pvsegs_sort="pv_name,pvseg_start"
pvsegs_cols="pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size"
pvsegs_cols_verbose="pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size,lv_name,seg_start_pe,segtype,seg_pe_ranges"
mark_hidden_devices=1
}

View File

@ -1109,8 +1109,8 @@ activation {
# @*
# Selects an LV if a tag defined on the host is also set on the LV
# or VG. See tags/hosttags. If any host tags exist but volume_list
# is not defined, a default single-entry list containing '@*' is
# assumed.
# is not defined, a default single-entry list containing '@*'
# is assumed.
#
# Example
# volume_list = [ "vg1", "vg2/lvol1", "@tag1", "@*" ]
@ -1146,11 +1146,11 @@ activation {
# @*
# Selects an LV if a tag defined on the host is also set on the LV
# or VG. See tags/hosttags. If any host tags exist but volume_list
# is not defined, a default single-entry list containing '@*' is
# assumed.
# is not defined, a default single-entry list containing '@*'
# is assumed.
#
# Example
# volume_list = [ "vg1", "vg2/lvol1", "@tag1", "@*" ]
# auto_activation_volume_list = [ "vg1", "vg2/lvol1", "@tag1", "@*" ]
#
# This configuration option does not have a default value defined.
@ -1172,11 +1172,11 @@ activation {
# @*
# Selects an LV if a tag defined on the host is also set on the LV
# or VG. See tags/hosttags. If any host tags exist but volume_list
# is not defined, a default single-entry list containing '@*' is
# assumed.
# is not defined, a default single-entry list containing '@*'
# is assumed.
#
# Example
# volume_list = [ "vg1", "vg2/lvol1", "@tag1", "@*" ]
# read_only_volume_list = [ "vg1", "vg2/lvol1", "@tag1", "@*" ]
#
# This configuration option does not have a default value defined.
@ -1415,6 +1415,17 @@ activation {
# This configuration section has an automatic default value.
# metadata {
# Configuration option metadata/check_pv_device_sizes.
# Check device sizes are not smaller than corresponding PV sizes.
# If device size is less than corresponding PV size found in metadata,
# there is always a risk of data loss. If this option is set, then LVM
# issues a warning message each time it finds that the device size is
# less than corresponding PV size. You should not disable this unless
# you are absolutely sure about what you are doing!
# This configuration option is advanced.
# This configuration option has an automatic default value.
# check_pv_device_sizes = 1
# Configuration option metadata/pvmetadatacopies.
# Number of copies of metadata to store on each PV.
# The --pvmetadatacopies option overrides this setting.
@ -1808,6 +1819,11 @@ activation {
# See 'pvs --segments -o help' for the list of possible fields.
# This configuration option has an automatic default value.
# pvsegs_cols_verbose = "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size,lv_name,seg_start_pe,segtype,seg_pe_ranges"
# Configuration option report/mark_hidden_devices.
# Use brackets [] to mark hidden devices.
# This configuration option has an automatic default value.
# mark_hidden_devices = 1
# }
# Configuration section dmeventd.

1182
configure vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
###############################################################################
## Copyright (C) 2000-2004 Sistina Software, Inc. All rights reserved.
## Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
## Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved.
##
## This copyrighted material is made available to anyone wishing to use,
## modify, copy, or redistribute it subject to the terms and conditions
@ -8,10 +8,10 @@
##
## 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
## Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
################################################################################
AC_PREREQ(2.61)
AC_PREREQ(2.69)
################################################################################
dnl -- Process this file with autoconf to produce a configure script.
AC_INIT
@ -39,7 +39,6 @@ case "$host_os" in
DEVMAPPER=yes
LVMETAD=no
LVMPOLLD=no
LVMLOCKD=no
LOCKDSANLOCK=no
LOCKDDLM=no
ODIRECT=yes
@ -86,6 +85,7 @@ AC_PROG_MKDIR_P
AC_PROG_RANLIB
AC_PATH_TOOL(CFLOW_CMD, cflow)
AC_PATH_TOOL(CSCOPE_CMD, cscope)
AC_PATH_TOOL(CHMOD, chmod)
################################################################################
dnl -- Check for header files.
@ -1145,6 +1145,8 @@ AC_MSG_RESULT($LVMPOLLD)
BUILD_LVMPOLLD=$LVMPOLLD
################################################################################
BUILD_LVMLOCKD=no
dnl -- Build lockdsanlock
AC_MSG_CHECKING(whether to build lockdsanlock)
AC_ARG_ENABLE(lockd-sanlock,
@ -1155,14 +1157,10 @@ 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)
PKG_CHECK_MODULES(LOCKD_SANLOCK, libsanlock_client >= 3.3.0, [HAVE_LOCKD_SANLOCK=yes], $bailout)
AC_DEFINE([LOCKDSANLOCK_SUPPORT], 1, [Define to 1 to include code that uses lvmlockd sanlock option.])
BUILD_LVMLOCKD=yes
fi
@ -1177,20 +1175,15 @@ 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)
AC_DEFINE([LOCKDDLM_SUPPORT], 1, [Define to 1 to include code that uses lvmlockd dlm option.])
BUILD_LVMLOCKD=yes
fi
################################################################################
dnl -- Build lvmlockd
AC_MSG_CHECKING(whether to build lvmlockd)
AC_MSG_RESULT($BUILD_LVMLOCKD)
@ -1299,7 +1292,7 @@ if test "$BLKID_WIPING" != no; then
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
DEFAULT_USE_BLKID_WIPING=0
fi
else
DEFAULT_USE_BLKID_WIPING=0
@ -1342,6 +1335,10 @@ if test "$UDEV_SYNC" = yes; then
pkg_config_init
PKG_CHECK_MODULES(UDEV, libudev >= 143, [UDEV_PC="libudev"])
AC_DEFINE([UDEV_SYNC_SUPPORT], 1, [Define to 1 to enable synchronisation with udev processing.])
AC_CHECK_LIB(udev, udev_device_get_is_initialized, AC_DEFINE([HAVE_LIBUDEV_UDEV_DEVICE_GET_IS_INITIALIZED], 1,
[Define to 1 if udev_device_get_is_initialized is available.]))
LIBS=$ac_check_lib_save_LIBS
fi
dnl -- Enable udev rules
@ -1441,25 +1438,76 @@ test "$CMDLIB" = yes \
&& LVM2CMD_LIB=-llvm2cmd \
|| LVM2CMD_LIB=
################################################################################
dnl -- Enable D-Bus service
AC_MSG_CHECKING(whether to include Python D-Bus support)
AC_ARG_ENABLE(dbus-service,
AC_HELP_STRING([--enable-dbus-service], [install D-Bus support]),
BUILD_LVMDBUSD=$enableval, BUILD_LVMDBUSD=no)
AC_MSG_RESULT($BUILD_LVMDBUSD)
################################################################################
dnl -- Enable Python liblvm2app bindings
AC_MSG_CHECKING(whether to build Python wrapper for liblvm2app.so)
AC_ARG_ENABLE(python_bindings,
AC_HELP_STRING([--enable-python_bindings], [build Python applib bindings]),
AC_HELP_STRING([--enable-python_bindings], [build default Python applib bindings]),
PYTHON_BINDINGS=$enableval, PYTHON_BINDINGS=no)
AC_MSG_RESULT($PYTHON_BINDINGS)
AC_MSG_CHECKING(whether to build Python2 wrapper for liblvm2app.so)
AC_ARG_ENABLE(python2_bindings,
AC_HELP_STRING([--enable-python2_bindings], [build Python2 applib bindings]),
PYTHON2_BINDINGS=$enableval, PYTHON2_BINDINGS=no)
AC_MSG_RESULT($PYTHON2_BINDINGS)
AC_MSG_CHECKING(whether to build Python3 wrapper for liblvm2app.so)
AC_ARG_ENABLE(python3_bindings,
AC_HELP_STRING([--enable-python3_bindings], [build Python3 applib bindings]),
PYTHON3_BINDINGS=$enableval, PYTHON3_BINDINGS=no)
AC_MSG_RESULT($PYTHON3_BINDINGS)
if test "$PYTHON_BINDINGS" = yes; then
test "$APPLIB" != yes && AC_MSG_ERROR([--enable-python_bindings requires --enable-applib])
AC_MSG_ERROR([--enable-python-bindings is replaced by --enable-python2-bindings and --enable-python3-bindings])
fi
AC_PATH_TOOL(PYTHON, python)
test -z "$PYTHON" && AC_MSG_ERROR([python is required for --enable-python_bindings but cannot be found])
if test "$PYTHON2_BINDINGS" = yes; then
AM_PATH_PYTHON([2])
AC_PATH_TOOL(PYTHON2, python2)
test -z "$PYTHON2" && AC_MSG_ERROR([python2 is required for --enable-python2_bindings but cannot be found])
AC_PATH_TOOL(PYTHON2_CONFIG, python2-config)
test -z "$PYTHON2_CONFIG" && AC_PATH_TOOL(PYTHON2_CONFIG, python-config)
test -z "$PYTHON2_CONFIG" && AC_MSG_ERROR([python headers are required for --enable-python2_bindings but cannot be found])
PYTHON2_INCDIRS=`"$PYTHON2_CONFIG" --includes`
PYTHON2_LIBDIRS=`"$PYTHON2_CONFIG" --libs`
PYTHON2DIR=$pythondir
PYTHON_BINDINGS=yes
fi
if test "$PYTHON3_BINDINGS" = yes -o "$BUILD_LVMDBUSD" = yes; then
unset PYTHON PYTHON_CONFIG
unset am_cv_pathless_PYTHON ac_cv_path_PYTHON am_cv_python_platform
unset am_cv_python_pythondir am_cv_python_version am_cv_python_pyexecdir
unset ac_cv_path_PYTHON_CONFIG ac_cv_path_ac_pt_PYTHON_CONFIG
AM_PATH_PYTHON([3])
PYTHON3=$PYTHON
test -z "$PYTHON3" && AC_MSG_ERROR([python3 is required for --enable-python3_bindings or --enable-dbus-service but cannot be found])
AC_PATH_TOOL(PYTHON3_CONFIG, python3-config)
test -z "$PYTHON3_CONFIG" && AC_MSG_ERROR([python3 headers are required for --enable-python3_bindings or --enable-dbus-service but cannot be found])
PYTHON3_INCDIRS=`"$PYTHON3_CONFIG" --includes`
PYTHON3_LIBDIRS=`"$PYTHON3_CONFIG" --libs`
PYTHON3DIR=$pythondir
PYTHON_BINDINGS=yes
fi
AC_PATH_TOOL(PYTHON_CONFIG, python-config)
test -z "$PYTHON_CONFIG" && AC_MSG_ERROR([python headers are required for --enable-python_bindings but cannot be found])
if test "$BUILD_LVMDBUSD" = yes; then
# To get this macro, install autoconf-archive package then run autoreconf
AC_PYTHON_MODULE([pyudev], [Required], python3)
AC_PYTHON_MODULE([dbus], [Required], python3)
fi
PYTHON_INCDIRS=`"$PYTHON_CONFIG" --includes`
PYTHON_LIBDIRS=`"$PYTHON_CONFIG" --libs`
if test "$PYTHON_BINDINGS" = yes -o "$PYTHON2_BINDINGS" = yes -o "$PYTHON3_BINDINGS" = yes; then
test "$APPLIB" != yes && AC_MSG_ERROR([Python_bindings require --enable-applib])
fi
################################################################################
@ -1911,6 +1959,7 @@ AC_SUBST(AWK)
AC_SUBST(BLKID_PC)
AC_SUBST(BUILD_CMIRRORD)
AC_SUBST(BUILD_DMEVENTD)
AC_SUBST(BUILD_LVMDBUSD)
AC_SUBST(BUILD_LVMETAD)
AC_SUBST(BUILD_LVMPOLLD)
AC_SUBST(BUILD_LVMLOCKD)
@ -1919,6 +1968,7 @@ AC_SUBST(BUILD_LOCKDDLM)
AC_SUBST(CACHE)
AC_SUBST(CFLAGS)
AC_SUBST(CFLOW_CMD)
AC_SUBST(CHMOD)
AC_SUBST(CLDFLAGS)
AC_SUBST(CLDNOWHOLEARCHIVE)
AC_SUBST(CLDWHOLEARCHIVE)
@ -1995,10 +2045,17 @@ AC_SUBST(PKGCONFIG)
AC_SUBST(POOL)
AC_SUBST(M_LIBS)
AC_SUBST(PTHREAD_LIBS)
AC_SUBST(PYTHON)
AC_SUBST(PYTHON2)
AC_SUBST(PYTHON3)
AC_SUBST(PYTHON_BINDINGS)
AC_SUBST(PYTHON_INCDIRS)
AC_SUBST(PYTHON_LIBDIRS)
AC_SUBST(PYTHON2_BINDINGS)
AC_SUBST(PYTHON3_BINDINGS)
AC_SUBST(PYTHON2_INCDIRS)
AC_SUBST(PYTHON3_INCDIRS)
AC_SUBST(PYTHON2_LIBDIRS)
AC_SUBST(PYTHON3_LIBDIRS)
AC_SUBST(PYTHON2DIR)
AC_SUBST(PYTHON3DIR)
AC_SUBST(QUORUM_CFLAGS)
AC_SUBST(QUORUM_LIBS)
AC_SUBST(RAID)
@ -2070,6 +2127,8 @@ daemons/dmeventd/plugins/raid/Makefile
daemons/dmeventd/plugins/mirror/Makefile
daemons/dmeventd/plugins/snapshot/Makefile
daemons/dmeventd/plugins/thin/Makefile
daemons/lvmdbusd/Makefile
daemons/lvmdbusd/path.py
daemons/lvmetad/Makefile
daemons/lvmpolld/Makefile
daemons/lvmlockd/Makefile
@ -2107,12 +2166,14 @@ scripts/blk_availability_init_red_hat
scripts/blk_availability_systemd_red_hat.service
scripts/clvmd_init_red_hat
scripts/cmirrord_init_red_hat
scripts/com.redhat.lvmdbus1.service
scripts/dm_event_systemd_red_hat.service
scripts/dm_event_systemd_red_hat.socket
scripts/lvm2_cluster_activation_red_hat.sh
scripts/lvm2_cluster_activation_systemd_red_hat.service
scripts/lvm2_clvmd_systemd_red_hat.service
scripts/lvm2_cmirrord_systemd_red_hat.service
scripts/lvm2_lvmdbusd_systemd_red_hat.service
scripts/lvm2_lvmetad_init_red_hat
scripts/lvm2_lvmetad_systemd_red_hat.service
scripts/lvm2_lvmetad_systemd_red_hat.socket

122
coverity/coverity_model.c Normal file
View File

@ -0,0 +1,122 @@
/*
* Copyright (C) 2015 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* Coverity usage:
*
* translate model into xml
* cov-make-library -of coverity_model.xml coverity_model.c
*
* compile (using outdir 'cov'):
* cov-build --dir=cov make CC=gcc
*
* analyze (agressively, using 'cov')
* cov-analyze --dir cov --wait-for-license --hfa --concurrency --enable-fnptr --enable-constraint-fpp --security --all --aggressiveness-level=high --field-offset-escape --user-model-file=coverity/coverity_model.xml
*
* generate html output (to 'html' from 'cov'):
* cov-format-errors --dir cov --html-output html
*/
struct lv_segment;
struct logical_volume;
struct lv_segment *first_seg(const struct logical_volume *lv)
{
return ((struct lv_segment **)lv)[0];
}
struct lv_segment *last_seg(const struct logical_volume *lv)
{
return ((struct lv_segment **)lv)[0];
}
/* simple_memccpy() from glibc */
void *memccpy(void *dest, const void *src, int c, size_t n)
{
const char *s = src;
char *d = dest;
while (n-- > 0)
if ((*d++ = *s++) == (char) c)
return d;
return 0;
}
/*
* 2 lines bellow needs to be placed in coverity/config/user_nodefs.h
* Not sure about any other way.
* Without them, coverity shows warning since x86 system header files
* are using inline assembly to reset fdset
*/
//#nodef FD_ZERO model_FD_ZERO
//void model_FD_ZERO(void *fdset);
void model_FD_ZERO(void *fdset)
{
unsigned i;
for (i = 0; i < 1024 / 8 / sizeof(long); ++i)
((long*)fdset)[i] = 0;
}
/*
* Added extra pointer check to not need these models,
* for now just keep then in file
*/
/*
struct cmd_context;
struct profile;
const char *find_config_tree_str(struct cmd_context *cmd, int id, struct profile *profile)
{
return "text";
}
const char *find_config_tree_str_allow_empty(struct cmd_context *cmd, int id, struct profile *profile)
{
return "text";
}
*/
/*
* Until fixed coverity case# 00531860:
* A FORWARD_NULL false positive on a recursive function call
*
* model also these functions:
*/
/*
const struct dm_config_node;
const struct dm_config_node *find_config_tree_array(struct cmd_context *cmd, int id, struct profile *profile)
{
const struct dm_config_node *cn;
return cn;
}
const struct dm_config_node *find_config_tree_node(struct cmd_context *cmd, int id, struct profile *profile)
{
const struct dm_config_node *cn;
return cn;
}
int find_config_tree_bool(struct cmd_context *cmd, int id, struct profile *profile)
{
int b;
return b;
}
*/

View File

@ -9,7 +9,7 @@
#
# 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
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@
@ -44,8 +44,12 @@ ifeq ("@BUILD_LVMLOCKD@", "yes")
SUBDIRS += lvmlockd
endif
ifeq ("@BUILD_LVMDBUSD@", "yes")
SUBDIRS += lvmdbusd
endif
ifeq ($(MAKECMDGOALS),distclean)
SUBDIRS = clvmd cmirrord dmeventd lvmetad lvmpolld lvmlockd
SUBDIRS = clvmd cmirrord dmeventd lvmetad lvmpolld lvmlockd lvmdbusd
endif
include $(top_builddir)/make.tmpl

View File

@ -9,7 +9,7 @@
#
# 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
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@

View File

@ -10,7 +10,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* Definitions for CLVMD server and clients */
@ -50,7 +50,7 @@ struct clvm_header {
#define CLVMD_FLAG_REMOTE 8 /* Do this on all nodes except for the local node */
/* Name of the local socket to communicate between lvm and clvmd */
static const char CLVMD_SOCKNAME[]= DEFAULT_RUN_DIR "/clvmd.sock";
#define CLVMD_SOCKNAME DEFAULT_RUN_DIR "/clvmd.sock"
/* Internal commands & replies */
#define CLVMD_CMD_REPLY 1
@ -76,8 +76,10 @@ static const char CLVMD_SOCKNAME[]= DEFAULT_RUN_DIR "/clvmd.sock";
#define CLVMD_CMD_SYNC_NAMES 45
/* Used internally by some callers, but not part of the protocol.*/
#define NODE_ALL "*"
#define NODE_LOCAL "."
#define NODE_REMOTE "^"
#ifndef NODE_ALL
# define NODE_ALL "*"
# define NODE_LOCAL "."
# define NODE_REMOTE "^"
#endif
#endif

View File

@ -10,7 +10,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*

View File

@ -10,7 +10,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*

View File

@ -9,7 +9,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*

View File

@ -10,7 +10,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*

View File

@ -9,7 +9,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*

View File

@ -9,7 +9,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*

View File

@ -9,7 +9,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "clvmd-common.h"

View File

@ -10,7 +10,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
@ -374,7 +374,7 @@ int main(int argc, char *argv[])
/* Deal with command-line arguments */
opterr = 0;
optind = 0;
while ((opt = getopt_long(argc, argv, "vVhfd:t:RST:CI:E:",
while ((opt = getopt_long(argc, argv, "Vhfd:t:RST:CI:E:",
longopts, NULL)) != -1) {
switch (opt) {
case 'h':
@ -604,7 +604,10 @@ int main(int argc, char *argv[])
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);
if (pthread_create(&lvm_thread, &stack_attr, lvm_thread_fn, &lvm_params)) {
log_sys_error("pthread_create", "");
goto out;
}
/* Don't start until the LVM thread is ready */
pthread_barrier_wait(&lvm_start_barrier);

View File

@ -10,7 +10,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _CLVMD_H

View File

@ -10,7 +10,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "clvmd-common.h"
@ -291,6 +291,7 @@ static int hold_lock(char *resource, int mode, int flags)
}
lvi->lock_mode = mode;
lvi->lock_id = 0;
status = sync_lock(resource, mode, flags & ~LCKF_CONVERT, &lvi->lock_id);
saved_errno = errno;
if (status) {
@ -662,7 +663,8 @@ int do_refresh_cache(void)
init_full_scan_done(0);
init_ignore_suspended_devices(1);
lvmcache_label_scan(cmd, 2);
lvmcache_force_next_label_scan();
lvmcache_label_scan(cmd);
dm_pool_empty(cmd->mem);
pthread_mutex_unlock(&lvm_lock);
@ -899,8 +901,12 @@ int init_clvm(struct dm_hash_table *excl_uuid)
if (!get_initial_state(excl_uuid))
log_error("Cannot load initial lock states.");
if (!udev_init_library_context())
stack;
if (!(cmd = create_toolcontext(1, NULL, 0, 1, 1, 1))) {
log_error("Failed to allocate command context");
udev_fin_library_context();
return 0;
}
@ -927,6 +933,7 @@ void destroy_lvm(void)
if (cmd) {
memlock_dec_daemon(cmd);
destroy_toolcontext(cmd);
udev_fin_library_context();
cmd = NULL;
}
}

View File

@ -10,7 +10,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* Functions in lvm-functions.c */

View File

@ -10,7 +10,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* FIXME Remove duplicated functions from this file. */

View File

@ -9,7 +9,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

View File

@ -9,7 +9,7 @@
#
# 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
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@

View File

@ -7,7 +7,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "logging.h"
#include "common.h"

View File

@ -7,7 +7,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "logging.h"
#include "cluster.h"
@ -1440,7 +1440,7 @@ static void cpg_leave_callback(struct clog_cpg *match,
free(rq);
}
}
for (i = 0, j = 0; i < match->checkpoints_needed; i++, j++) {
for (i = 0, j = 0; (int) i < match->checkpoints_needed; i++, j++) {
match->checkpoint_requesters[j] = match->checkpoint_requesters[i];
if (match->checkpoint_requesters[i] == left->nodeid) {
LOG_ERROR("[%s] Removing pending ckpt from needed list (%u is leaving)",

View File

@ -7,7 +7,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _LVM_CLOG_CLUSTER_H
#define _LVM_CLOG_CLUSTER_H

View File

@ -7,7 +7,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _LVM_CLOG_COMMON_H
#define _LVM_CLOG_COMMON_H

View File

@ -7,7 +7,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "logging.h"
#include "functions.h"

View File

@ -7,7 +7,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _LVM_CLOG_FUNCTIONS_H
#define _LVM_CLOG_FUNCTIONS_H

View File

@ -7,7 +7,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "logging.h"
#include "link_mon.h"

View File

@ -7,7 +7,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _LVM_CLOG_LINK_MON_H
#define _LVM_CLOG_LINK_MON_H

View File

@ -7,7 +7,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "logging.h"
#include "common.h"

View File

@ -7,7 +7,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _LVM_CLOG_LOCAL_H
#define _LVM_CLOG_LOCAL_H

View File

@ -7,7 +7,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "logging.h"

View File

@ -7,7 +7,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _LVM_CLOG_LOGGING_H

View File

@ -9,7 +9,7 @@
#
# 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
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@

View File

@ -9,7 +9,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
@ -408,7 +408,7 @@ static struct thread_status *_alloc_thread_status(const struct message_data *dat
if (!(thread->device.uuid = dm_strdup(data->device_uuid)))
goto_out;
/* Until real name resolved, use UUID */
/* Until real name resolved, use UUID */
if (!(thread->device.name = dm_strdup(data->device_uuid)))
goto_out;
@ -1355,78 +1355,89 @@ static int _get_timeout(struct message_data *message_data)
return (msg->data && msg->size) ? 0 : -ENOMEM;
}
/* Open fifos used for client communication. */
static int _open_fifos(struct dm_event_fifos *fifos)
static int _open_fifo(const char *path)
{
struct stat st;
int fd = -1;
/*
* FIXME Explicitly verify the code's requirement that path is secure:
* - All parent directories owned by root without group/other write access unless sticky.
*/
/* Create client fifo. */
(void) dm_prepare_selinux_context(fifos->client_path, S_IFIFO);
if ((mkfifo(fifos->client_path, 0600) == -1) && errno != EEXIST) {
log_sys_error("client mkfifo", fifos->client_path);
(void) dm_prepare_selinux_context(NULL, 0);
goto fail;
/* If path exists, only use it if it is root-owned fifo mode 0600 */
if ((lstat(path, &st) < 0)) {
if (errno != ENOENT) {
log_sys_error("stat", path);
return -1;
}
} else if (!S_ISFIFO(st.st_mode) || st.st_uid ||
(st.st_mode & (S_IEXEC | S_IRWXG | S_IRWXO))) {
log_warn("WARNING: %s has wrong attributes: Replacing.", path);
if (unlink(path)) {
log_sys_error("unlink", path);
return -1;
}
}
/* Create server fifo. */
(void) dm_prepare_selinux_context(fifos->server_path, S_IFIFO);
if ((mkfifo(fifos->server_path, 0600) == -1) && errno != EEXIST) {
log_sys_error("server mkfifo", fifos->server_path);
/* Create fifo. */
(void) dm_prepare_selinux_context(path, S_IFIFO);
if ((mkfifo(path, 0600) == -1) && errno != EEXIST) {
log_sys_error("mkfifo", path);
(void) dm_prepare_selinux_context(NULL, 0);
goto fail;
}
(void) dm_prepare_selinux_context(NULL, 0);
/* Warn about wrong permissions if applicable */
if ((!stat(fifos->client_path, &st)) && (st.st_mode & 0777) != 0600)
log_warn("WARNING: Fixing wrong permissions on %s: %s.\n",
fifos->client_path, strerror(errno));
if ((!stat(fifos->server_path, &st)) && (st.st_mode & 0777) != 0600)
log_warn("WARNING: Fixing wrong permissions on %s: %s.\n",
fifos->server_path, strerror(errno));
/* If they were already there, make sure permissions are ok. */
if (chmod(fifos->client_path, 0600)) {
log_sys_error("chmod", fifos->client_path);
goto fail;
}
if (chmod(fifos->server_path, 0600)) {
log_sys_error("chmod", fifos->server_path);
goto fail;
}
/* Need to open read+write or we will block or fail */
if ((fifos->server = open(fifos->server_path, O_RDWR)) < 0) {
log_sys_error("server open", fifos->server_path);
if ((fd = open(path, O_RDWR)) < 0) {
log_sys_error("open", path);
goto fail;
}
if (fcntl(fifos->server, F_SETFD, FD_CLOEXEC) < 0) {
log_sys_error("fcntl(FD_CLOEXEC)", fifos->server_path);
/* Warn about wrong permissions if applicable */
if (fstat(fd, &st)) {
log_sys_error("fstat", path);
goto fail;
}
/* Need to open read+write for select() to work. */
if ((fifos->client = open(fifos->client_path, O_RDWR)) < 0) {
log_sys_error("client open", fifos->client_path);
if (!S_ISFIFO(st.st_mode) || st.st_uid ||
(st.st_mode & (S_IEXEC | S_IRWXG | S_IRWXO))) {
log_error("%s: fifo has incorrect attributes", path);
goto fail;
}
if (fcntl(fifos->client, F_SETFD, FD_CLOEXEC) < 0) {
log_sys_error("fcntl(FD_CLOEXEC)", fifos->client_path);
if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
log_sys_error("fcntl(FD_CLOEXEC)", path);
goto fail;
}
return fd;
fail:
if ((fd >= 0) && close(fd))
log_sys_error("close", path);
return -1;
}
/* Open fifos used for client communication. */
static int _open_fifos(struct dm_event_fifos *fifos)
{
/* Create client fifo. */
if ((fifos->client = _open_fifo(fifos->client_path)) < 0)
goto fail;
/* Create server fifo. */
if ((fifos->server = _open_fifo(fifos->server_path)) < 0)
goto fail;
return 1;
fail:
if (fifos->server >= 0 && close(fifos->server))
log_sys_error("server close", fifos->server_path);
fail:
if (fifos->client >= 0 && close(fifos->client))
log_sys_error("client close", fifos->client_path);
log_sys_error("close", fifos->client_path);
return 0;
}
@ -1961,21 +1972,21 @@ static int _reinstate_registrations(struct dm_event_fifos *fifos)
!(dev_name = strtok(NULL, _delim)) ||
!(mask = strtok(NULL, _delim)) ||
!(timeout = strtok(NULL, _delim))) {
fprintf(stderr, _failed_parsing_msg);
fputs(_failed_parsing_msg, stderr);
continue;
}
errno = 0;
mask_value = strtoul(mask, &endp, 10);
if (errno || !endp || *endp) {
fprintf(stderr, _failed_parsing_msg);
fputs(_failed_parsing_msg, stderr);
continue;
}
errno = 0;
timeout_value = strtoul(timeout, &endp, 10);
if (errno || !endp || *endp) {
fprintf(stderr, _failed_parsing_msg);
fputs(_failed_parsing_msg, stderr);
continue;
}
@ -2260,9 +2271,9 @@ int main(int argc, char *argv[])
log_notice("dmeventd shutting down.");
if (close(fifos.client))
if (fifos.client >= 0 && close(fifos.client))
log_sys_error("client close", fifos.client_path);
if (close(fifos.server))
if (fifos.server >= 0 && close(fifos.server))
log_sys_error("server close", fifos.server_path);
if (_use_syslog)

View File

@ -9,7 +9,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __DMEVENTD_DOT_H__

View File

@ -9,7 +9,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "dm-logging.h"
@ -412,28 +412,55 @@ static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos)
char default_dmeventd_path[] = DMEVENTD_PATH;
char *args[] = { dmeventd_path ? : default_dmeventd_path, NULL };
if (stat(fifos->client_path, &statbuf))
goto start_server;
/*
* FIXME Explicitly verify the code's requirement that client_path is secure:
* - All parent directories owned by root without group/other write access unless sticky.
*/
if (!S_ISFIFO(statbuf.st_mode)) {
log_error("%s is not a fifo.", fifos->client_path);
/* If client fifo path exists, only use it if it is root-owned fifo mode 0600 */
if ((lstat(fifos->client_path, &statbuf) < 0)) {
if (errno == ENOENT)
/* Jump ahead if fifo does not already exist. */
goto start_server;
else {
log_sys_error("stat", fifos->client_path);
return 0;
}
} else if (!S_ISFIFO(statbuf.st_mode)) {
log_error("%s must be a fifo.", fifos->client_path);
return 0;
} else if (statbuf.st_uid) {
log_error("%s must be owned by uid 0.", fifos->client_path);
return 0;
} else if (statbuf.st_mode & (S_IEXEC | S_IRWXG | S_IRWXO)) {
log_error("%s must have mode 0600.", fifos->client_path);
return 0;
}
/* Anyone listening? If not, errno will be ENXIO */
fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK);
if (fifos->client >= 0) {
/* Should never happen if all the above checks passed. */
if ((fstat(fifos->client, &statbuf) < 0) ||
!S_ISFIFO(statbuf.st_mode) || statbuf.st_uid ||
(statbuf.st_mode & (S_IEXEC | S_IRWXG | S_IRWXO))) {
log_error("%s is no longer a secure root-owned fifo with mode 0600.", fifos->client_path);
if (close(fifos->client))
log_sys_debug("close", fifos->client_path);
return 0;
}
/* server is running and listening */
if (close(fifos->client))
log_sys_debug("close", fifos->client_path);
return 1;
} else if (errno != ENXIO) {
} else if (errno != ENXIO && errno != ENOENT) {
/* problem */
log_sys_error("open", fifos->client_path);
return 0;
}
start_server:
start_server:
/* server is not running */
if ((args[0][0] == '/') && stat(args[0], &statbuf)) {
@ -587,8 +614,8 @@ static int _do_event(int cmd, char *dmeventd_path, struct dm_event_daemon_messag
};
if (!_init_client(dmeventd_path, &fifos)) {
stack;
return -ESRCH;
ret = -ESRCH;
goto_out;
}
ret = daemon_talk(&fifos, msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0);
@ -598,7 +625,7 @@ static int _do_event(int cmd, char *dmeventd_path, struct dm_event_daemon_messag
if (!ret)
ret = daemon_talk(&fifos, msg, cmd, dso_name, dev_name, evmask, timeout);
out:
/* what is the opposite of init? */
fini_fifos(&fifos);
@ -727,6 +754,7 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
uuid = dm_task_get_uuid(dmt);
/* FIXME Distinguish errors connecting to daemon */
if (_do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE :
DM_EVENT_CMD_GET_REGISTERED_DEVICE, dmevh->dmeventd_path,
&msg, dmevh->dso, uuid, dmevh->mask, 0)) {
@ -841,7 +869,7 @@ void dm_event_log(const char *subsys, int level, const char *file,
static time_t start = 0;
const char *indent = "";
FILE *stream = stdout;
int prio = -1;
int prio;
time_t now;
switch (level & ~(_LOG_STDERR | _LOG_ONCE)) {

View File

@ -9,7 +9,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*

View File

@ -10,7 +10,7 @@
#
# 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
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@

View File

@ -9,7 +9,7 @@
#
# 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
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@

View File

@ -9,7 +9,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "lib.h"

View File

@ -9,7 +9,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*

View File

@ -10,7 +10,7 @@
#
# 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
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@

View File

@ -9,13 +9,12 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "lib.h"
#include "libdevmapper-event.h"
#include "dmeventd_lvm.h"
#include "defaults.h"
/* FIXME Reformat to 80 char lines. */
@ -31,8 +30,9 @@ struct dso_state {
DM_EVENT_LOG_FN("mirr")
static int _process_status_code(const char status_code, const char *dev_name,
const char *dev_type, int r)
static void _process_status_code(dm_status_mirror_health_t health,
uint32_t major, uint32_t minor,
const char *dev_type, int *r)
{
/*
* A => Alive - No failures
@ -42,90 +42,60 @@ static int _process_status_code(const char status_code, const char *dev_name,
* R => Read - A read failure occurred, mirror data unaffected
* U => Unclassified failure (bug)
*/
if (status_code == 'F') {
log_error("%s device %s flush failed.", dev_type, dev_name);
r = ME_FAILURE;
} else if (status_code == 'S')
log_error("%s device %s sync failed.", dev_type, dev_name);
else if (status_code == 'R')
log_error("%s device %s read failed.", dev_type, dev_name);
else if (status_code != 'A') {
log_error("%s device %s has failed (%c).",
dev_type, dev_name, status_code);
r = ME_FAILURE;
switch (health) {
case DM_STATUS_MIRROR_ALIVE:
return;
case DM_STATUS_MIRROR_FLUSH_FAILED:
log_error("%s device %u:%u flush failed.",
dev_type, major, minor);
*r = ME_FAILURE;
break;
case DM_STATUS_MIRROR_SYNC_FAILED:
log_error("%s device %u:%u sync failed.",
dev_type, major, minor);
break;
case DM_STATUS_MIRROR_READ_FAILED:
log_error("%s device %u:%u read failed.",
dev_type, major, minor);
break;
default:
log_error("%s device %u:%u has failed (%c).",
dev_type, major, minor, (char)health);
*r = ME_FAILURE;
break;
}
return r;
}
static int _get_mirror_event(char *params)
static int _get_mirror_event(struct dso_state *state, char *params)
{
int i, r = ME_INSYNC;
char **args = NULL;
char *dev_status_str;
char *log_status_str;
char *sync_str;
char *p = NULL;
int log_argc, num_devs;
int r = ME_INSYNC;
unsigned i;
struct dm_status_mirror *ms;
/*
* dm core parms: 0 409600 mirror
* Mirror core parms: 2 253:4 253:5 400/400
* New-style failure params: 1 AA
* New-style log params: 3 cluster 253:3 A
* or 3 disk 253:3 A
* or 1 core
*/
/* number of devices */
if (!dm_split_words(params, 1, 0, &p))
goto out_parse;
if (!(num_devs = atoi(p)) ||
(num_devs > DEFAULT_MIRROR_MAX_IMAGES) || (num_devs < 0))
goto out_parse;
p += strlen(p) + 1;
/* devices names + "400/400" + "1 AA" + 1 or 3 log parms + NULL */
args = dm_malloc((num_devs + 7) * sizeof(char *));
if (!args || dm_split_words(p, num_devs + 7, 0, args) < num_devs + 5)
goto out_parse;
/* FIXME: Code differs from lib/mirror/mirrored.c */
dev_status_str = args[2 + num_devs];
log_argc = atoi(args[3 + num_devs]);
log_status_str = args[3 + num_devs + log_argc];
sync_str = args[num_devs];
if (!dm_get_status_mirror(state->mem, params, &ms))
goto_out;
/* Check for bad mirror devices */
for (i = 0; i < num_devs; i++)
r = _process_status_code(dev_status_str[i], args[i],
i ? "Secondary mirror" : "Primary mirror", r);
for (i = 0; i < ms->dev_count; ++i)
_process_status_code(ms->devs[i].health,
ms->devs[i].major, ms->devs[i].minor,
i ? "Secondary mirror" : "Primary mirror", &r);
/* Check for bad disk log device */
if (log_argc > 1)
r = _process_status_code(log_status_str[0],
args[2 + num_devs + log_argc],
"Log", r);
for (i = 0; i < ms->log_count; ++i)
_process_status_code(ms->logs[i].health,
ms->logs[i].major, ms->logs[i].minor,
"Log", &r);
if (r == ME_FAILURE)
goto out;
/* Ignore if not in-sync */
if ((r == ME_INSYNC) && (ms->insync_regions != ms->total_regions))
r = ME_IGNORE;
p = strstr(sync_str, "/");
if (p) {
p[0] = '\0';
if (strcmp(sync_str, p+1))
r = ME_IGNORE;
p[0] = '/';
} else
goto out_parse;
dm_pool_free(state->mem, ms);
out:
dm_free(args);
return r;
out_parse:
dm_free(args);
out:
log_error("Unable to parse mirror status string.");
return ME_IGNORE;
@ -172,7 +142,7 @@ void process_event(struct dm_task *dmt,
continue;
}
switch(_get_mirror_event(params)) {
switch(_get_mirror_event(state, params)) {
case ME_INSYNC:
/* FIXME: all we really know is that this
_part_ of the device is in sync

View File

@ -9,7 +9,7 @@
#
# 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
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@

View File

@ -9,7 +9,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "lib.h"

View File

@ -10,7 +10,7 @@
#
# 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
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@

View File

@ -9,7 +9,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "lib.h"

View File

@ -9,7 +9,7 @@
#
# 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
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@

View File

@ -9,7 +9,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "lib.h" /* using here lvm log */

View File

@ -0,0 +1,65 @@
#
# Copyright (C) 2016 Red Hat, Inc. All rights reserved.
#
# This file is part of LVM2.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
lvmdbusdir = $(python3dir)/lvmdbusd
LVMDBUS_SRCDIR_FILES = \
automatedproperties.py \
background.py \
cfg.py \
cmdhandler.py \
fetch.py \
__init__.py \
job.py \
loader.py \
lvmdb.py \
main.py \
lvm_shell_proxy.py \
lv.py \
manager.py \
objectmanager.py \
pv.py \
refresh.py \
request.py \
state.py \
udevwatch.py \
utils.py \
vg.py
LVMDBUS_BUILDDIR_FILES = \
path.py
LVMDBUSD = $(srcdir)/lvmdbusd
include $(top_builddir)/make.tmpl
.PHONY: install_lvmdbusd
install_lvmdbusd:
$(INSTALL_DIR) $(sbindir)
$(INSTALL_SCRIPT) $(LVMDBUSD) $(sbindir)
$(INSTALL_DIR) $(DESTDIR)$(lvmdbusdir)
(cd $(srcdir); $(INSTALL_DATA) $(LVMDBUS_SRCDIR_FILES) $(DESTDIR)$(lvmdbusdir))
$(INSTALL_DATA) $(LVMDBUS_BUILDDIR_FILES) $(DESTDIR)$(lvmdbusdir)
PYTHON=$(PYTHON3) $(PYCOMPILE) --destdir "$(DESTDIR)" --basedir "$(lvmdbusdir)" $(LVMDBUS_SRCDIR_FILES) $(LVMDBUS_BUILDDIR_FILES)
$(CHMOD) 755 $(DESTDIR)$(lvmdbusdir)/__pycache__
$(CHMOD) 444 $(DESTDIR)$(lvmdbusdir)/__pycache__/*.py[co]
install_lvm2: install_lvmdbusd
install: install_lvm2

View File

@ -0,0 +1,10 @@
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from .main import main

View File

@ -0,0 +1,175 @@
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import dbus
from . import cfg
from .utils import get_properties, add_properties, get_object_property_diff, \
log_debug
from .state import State
# noinspection PyPep8Naming,PyUnresolvedReferences
class AutomatedProperties(dbus.service.Object):
"""
This class implements the needed interfaces for:
org.freedesktop.DBus.Properties
Other classes inherit from it to get the same behavior
"""
def __init__(self, object_path, search_method=None):
dbus.service.Object.__init__(self, cfg.bus, object_path)
self._ap_interface = []
self._ap_o_path = object_path
self._ap_search_method = search_method
self.state = None
def dbus_object_path(self):
return self._ap_o_path
def emit_data(self):
props = {}
for i in self.interface():
props[i] = self.GetAll(i)
return self._ap_o_path, props
def set_interface(self, interface):
"""
With inheritance we can't easily tell what interfaces a class provides
so we will have each class that implements an interface tell the
base AutomatedProperties what it is they do provide. This is kind of
clunky and perhaps we can figure out a better way to do this later.
:param interface: An interface the object supports
:return:
"""
if interface not in self._ap_interface:
self._ap_interface.append(interface)
# noinspection PyUnusedLocal
def interface(self, all_interfaces=False):
if all_interfaces:
cpy = list(self._ap_interface)
cpy.extend(
["org.freedesktop.DBus.Introspectable",
"org.freedesktop.DBus.Properties"])
return cpy
return self._ap_interface
# Properties
# noinspection PyUnusedLocal
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
in_signature='ss', out_signature='v')
def Get(self, interface_name, property_name):
value = getattr(self, property_name)
# Note: If we get an exception in this handler we won't know about it,
# only the side effect of no returned value!
log_debug('Get (%s), type (%s), value(%s)' %
(property_name, str(type(value)), str(value)))
return value
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
in_signature='s', out_signature='a{sv}')
def GetAll(self, interface_name):
if interface_name in self.interface(True):
# Using introspection, lets build this dynamically
properties = get_properties(self)
if interface_name in properties:
return properties[interface_name][1]
return {}
raise dbus.exceptions.DBusException(
self._ap_interface,
'The object %s does not implement the %s interface'
% (self.__class__, interface_name))
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
in_signature='ssv')
def Set(self, interface_name, property_name, new_value):
setattr(self, property_name, new_value)
self.PropertiesChanged(interface_name,
{property_name: new_value}, [])
# As dbus-python does not support introspection for properties we will
# get the autogenerated xml and then add our wanted properties to it.
@dbus.service.method(dbus_interface=dbus.INTROSPECTABLE_IFACE,
out_signature='s')
def Introspect(self):
r = dbus.service.Object.Introspect(self, self._ap_o_path, cfg.bus)
# Look at the properties in the class
props = get_properties(self)
for int_f, v in props.items():
r = add_properties(r, int_f, v[0])
return r
@dbus.service.signal(dbus_interface=dbus.PROPERTIES_IFACE,
signature='sa{sv}as')
def PropertiesChanged(self, interface_name, changed_properties,
invalidated_properties):
log_debug(('SIGNAL: PropertiesChanged(%s, %s, %s, %s)' %
(str(self._ap_o_path), str(interface_name),
str(changed_properties), str(invalidated_properties))))
def refresh(self, search_key=None, object_state=None):
"""
Take the values (properties) of an object and update them with what
lvm currently has. You can either fetch the new ones or supply the
new state to be updated with
:param search_key: The value to use to search for
:param object_state: Use this as the new object state
"""
num_changed = 0
# If we can't do a lookup, bail now, this happens if we blindly walk
# through all dbus objects as some don't have a search method, like
# 'Manager' object.
if not self._ap_search_method:
return
search = self.lvm_id
if search_key:
search = search_key
# Either we have the new object state or we need to go fetch it
if object_state:
new_state = object_state
else:
new_state = self._ap_search_method([search])[0]
assert isinstance(new_state, State)
assert new_state
# When we refresh an object the object identifiers might have changed
# because LVM allows the user to change them (name & uuid), thus if
# they have changed we need to update the object manager so that
# look-ups will happen correctly
old_id = self.state.identifiers()
new_id = new_state.identifiers()
if old_id[0] != new_id[0] or old_id[1] != new_id[1]:
cfg.om.lookup_update(self, new_id[0], new_id[1])
# Grab the properties values, then replace the state of the object
# and retrieve the new values
# TODO: We need to add locking to prevent concurrent access to the
# properties so that a client is not accessing while we are
# replacing.
o_prop = get_properties(self)
self.state = new_state
n_prop = get_properties(self)
changed = get_object_property_diff(o_prop, n_prop)
if changed:
for int_f, v in changed.items():
self.PropertiesChanged(int_f, v, [])
num_changed += 1
return num_changed

View File

@ -0,0 +1,212 @@
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import threading
import subprocess
from . import cfg
import time
from .cmdhandler import options_to_cli_args
import dbus
from .job import Job, JobState
from .utils import pv_range_append, pv_dest_ranges, log_debug, log_error
from .request import RequestEntry
import traceback
_rlock = threading.RLock()
_thread_list = list()
def pv_move_lv_cmd(move_options, lv_full_name,
pv_source, pv_source_range, pv_dest_range_list):
cmd = ['pvmove', '-i', '1']
cmd.extend(options_to_cli_args(move_options))
if lv_full_name:
cmd.extend(['-n', lv_full_name])
pv_range_append(cmd, pv_source, *pv_source_range)
pv_dest_ranges(cmd, pv_dest_range_list)
return cmd
def lv_merge_cmd(merge_options, lv_full_name):
cmd = ['lvconvert', '--merge', '-i', '1']
cmd.extend(options_to_cli_args(merge_options))
cmd.append(lv_full_name)
return cmd
def _create_background_dbus_job(job_state):
job_obj = Job(None, job_state)
cfg.om.register_object(job_obj)
return job_obj.dbus_object_path()
def _move_merge(interface_name, cmd, time_out):
# Create job object to be used while running the command
rc = '/'
job_state = JobState(None)
add(cmd, job_state)
if time_out == -1:
# Waiting forever
done = job_state.Wait(time_out)
if not done:
ec, err_msg = job_state.GetError
raise dbus.exceptions.DBusException(
interface_name,
'Exit code %s, stderr = %s' % (str(ec), err_msg))
elif time_out == 0:
# Immediately create and return a job
rc = _create_background_dbus_job(job_state)
else:
# Willing to wait for a bit
done = job_state.Wait(time_out)
if not done:
rc = _create_background_dbus_job(job_state)
return rc
def move(interface_name, lv_name, pv_src_obj, pv_source_range,
pv_dests_and_ranges, move_options, time_out):
"""
Common code for the pvmove handling.
:param interface_name: What dbus interface we are providing for
:param lv_name: Optional (None or name of LV to move)
:param pv_src_obj: dbus object patch for source PV
:param pv_source_range: (0,0 to ignore, else start, end segments)
:param pv_dests_and_ranges: Array of PV object paths and start/end segs
:param move_options: Hash with optional arguments
:param time_out:
:return: Object path to job object
"""
pv_dests = []
pv_src = cfg.om.get_object_by_path(pv_src_obj)
if pv_src:
# Check to see if we are handling a move to a specific
# destination(s)
if len(pv_dests_and_ranges):
for pr in pv_dests_and_ranges:
pv_dbus_obj = cfg.om.get_object_by_path(pr[0])
if not pv_dbus_obj:
raise dbus.exceptions.DBusException(
interface_name,
'PV Destination (%s) not found' % pr[0])
pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
# Generate the command line for this command, but don't
# execute it.
cmd = pv_move_lv_cmd(move_options,
lv_name,
pv_src.lvm_id,
pv_source_range,
pv_dests)
return _move_merge(interface_name, cmd, time_out)
else:
raise dbus.exceptions.DBusException(
interface_name, 'pv_src_obj (%s) not found' % pv_src_obj)
def merge(interface_name, lv_uuid, lv_name, merge_options, time_out):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
if dbo:
cmd = lv_merge_cmd(merge_options, dbo.lvm_id)
return _move_merge(interface_name, cmd, time_out)
else:
raise dbus.exceptions.DBusException(
interface_name,
'LV with uuid %s and name %s not present!' % (lv_uuid, lv_name))
def background_reaper():
while cfg.run.value != 0:
with _rlock:
num_threads = len(_thread_list) - 1
if num_threads >= 0:
for i in range(num_threads, -1, -1):
_thread_list[i].join(0)
if not _thread_list[i].is_alive():
_thread_list.pop(i)
time.sleep(3)
def process_background_result(job_object, exit_code, error_msg):
cfg.load()
job_object.set_result(exit_code, error_msg)
return None
# noinspection PyUnusedLocal
def empty_cb(disregard):
pass
def background_execute(command, background_job, skip_first_line=False):
# Wrap this whole operation in an exception handler, otherwise if we
# hit a code bug we will silently exit this thread without anyone being
# the wiser.
try:
process = subprocess.Popen(command, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, close_fds=True)
lines_iterator = iter(process.stdout.readline, b"")
for line in lines_iterator:
line_str = line.decode("utf-8")
# Check to see if the line has the correct number of separators
try:
if line_str.count(':') == 2:
(device, ignore, percentage) = line_str.split(':')
background_job.Percent = \
round(float(percentage.strip()[:-1]), 1)
except ValueError:
log_error("Trying to parse percentage which failed for %s" %
line_str)
out = process.communicate()
if process.returncode == 0:
background_job.Percent = 100
# Queue up the result so that it gets executed in same thread as others.
r = RequestEntry(
-1, process_background_result,
(background_job, process.returncode, out[1]),
empty_cb, empty_cb, False)
cfg.worker_q.put(r)
except Exception:
# In the unlikely event that we blew up, lets notify fill out the
# job object so that the client doesn't hang potentially forever!
st = traceback.format_exc()
error = "Exception in background thread: \n%s" % st
log_error(error)
r = RequestEntry(
-1, process_background_result,
(background_job, 1, error),
empty_cb, empty_cb, False)
cfg.worker_q.put(r)
def add(command, reporting_job):
# Create the thread, get it running and then add it to the list
t = threading.Thread(
target=background_execute,
name="thread: " + ' '.join(command),
args=(command, reporting_job))
t.start()
with _rlock:
_thread_list.append(t)

80
daemons/lvmdbusd/cfg.py Normal file
View File

@ -0,0 +1,80 @@
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import multiprocessing
import queue
import itertools
try:
from . import path
except SystemError:
import path
LVM_CMD = os.getenv('LVM_BINARY', path.LVM_BINARY)
# This is the global object manager
om = None
# This is the global bus connection
bus = None
# Shared state variable across all processes
run = multiprocessing.Value('i', 1)
# Debug
DEBUG = True
# Use lvm shell
USE_SHELL = False
# Lock used by pprint
stdout_lock = multiprocessing.Lock()
kick_q = multiprocessing.Queue()
worker_q = queue.Queue()
# Main event loop
loop = None
BASE_INTERFACE = 'com.redhat.lvmdbus1'
PV_INTERFACE = BASE_INTERFACE + '.Pv'
VG_INTERFACE = BASE_INTERFACE + '.Vg'
LV_INTERFACE = BASE_INTERFACE + '.Lv'
LV_COMMON_INTERFACE = BASE_INTERFACE + '.LvCommon'
THIN_POOL_INTERFACE = BASE_INTERFACE + '.ThinPool'
CACHE_POOL_INTERFACE = BASE_INTERFACE + '.CachePool'
LV_CACHED = BASE_INTERFACE + '.CachedLv'
SNAPSHOT_INTERFACE = BASE_INTERFACE + '.Snapshot'
MANAGER_INTERFACE = BASE_INTERFACE + '.Manager'
JOB_INTERFACE = BASE_INTERFACE + '.Job'
BASE_OBJ_PATH = '/' + BASE_INTERFACE.replace('.', '/')
PV_OBJ_PATH = BASE_OBJ_PATH + '/Pv'
VG_OBJ_PATH = BASE_OBJ_PATH + '/Vg'
LV_OBJ_PATH = BASE_OBJ_PATH + '/Lv'
THIN_POOL_PATH = BASE_OBJ_PATH + "/ThinPool"
CACHE_POOL_PATH = BASE_OBJ_PATH + "/CachePool"
HIDDEN_LV_PATH = BASE_OBJ_PATH + "/HiddenLv"
MANAGER_OBJ_PATH = BASE_OBJ_PATH + '/Manager'
JOB_OBJ_PATH = BASE_OBJ_PATH + '/Job'
# Counters for object path generation
pv_id = itertools.count()
vg_id = itertools.count()
lv_id = itertools.count()
thin_id = itertools.count()
cache_pool_id = itertools.count()
job_id = itertools.count()
hidden_lv = itertools.count()
# Used to prevent circular imports...
load = None
# Global cached state
db = None

View File

@ -0,0 +1,629 @@
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from subprocess import Popen, PIPE
import time
import threading
from itertools import chain
try:
from . import cfg
from .utils import pv_dest_ranges, log_debug, log_error
from .lvm_shell_proxy import LVMShellProxy
except SystemError:
import cfg
from utils import pv_dest_ranges, log_debug, log_error
from lvm_shell_proxy import LVMShellProxy
SEP = '{|}'
total_time = 0.0
total_count = 0
# We need to prevent different threads from using the same lvm shell
# at the same time.
cmd_lock = threading.Lock()
# The actual method which gets called to invoke the lvm command, can vary
# from forking a new process to using lvm shell
_t_call = None
def _debug_c(cmd, exit_code, out):
log_error('CMD= %s' % ' '.join(cmd))
log_error(("EC= %d" % exit_code))
log_error(("STDOUT=\n %s\n" % out[0]))
log_error(("STDERR=\n %s\n" % out[1]))
def call_lvm(command, debug=False):
"""
Call an executable and return a tuple of exitcode, stdout, stderr
:param command: Command to execute
:param debug: Dump debug to stdout
"""
# print 'STACK:'
# for line in traceback.format_stack():
# print line.strip()
# Prepend the full lvm executable so that we can run different versions
# in different locations on the same box
command.insert(0, cfg.LVM_CMD)
process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True)
out = process.communicate()
stdout_text = bytes(out[0]).decode("utf-8")
stderr_text = bytes(out[1]).decode("utf-8")
if debug or process.returncode != 0:
_debug_c(command, process.returncode, (stdout_text, stderr_text))
if process.returncode == 0:
if cfg.DEBUG and out[1] and len(out[1]):
log_error('WARNING: lvm is out-putting text to STDERR on success!')
_debug_c(command, process.returncode, (stdout_text, stderr_text))
return process.returncode, stdout_text, stderr_text
def _shell_cfg():
global _t_call
log_debug('Using lvm shell!')
lvm_shell = LVMShellProxy()
_t_call = lvm_shell.call_lvm
if cfg.USE_SHELL:
_shell_cfg()
else:
_t_call = call_lvm
def set_execution(shell):
global _t_call
with cmd_lock:
_t_call = None
if shell:
log_debug('Using lvm shell!')
lvm_shell = LVMShellProxy()
_t_call = lvm_shell.call_lvm
else:
_t_call = call_lvm
def time_wrapper(command, debug=False):
global total_time
global total_count
with cmd_lock:
start = time.time()
results = _t_call(command, debug)
total_time += (time.time() - start)
total_count += 1
return results
call = time_wrapper
# Default cmd
# Place default arguments for every command here.
def _dc(cmd, args):
c = [cmd, '--noheading', '--separator', '%s' % SEP, '--nosuffix',
'--unbuffered', '--units', 'b']
c.extend(args)
return c
def parse(out):
rc = []
for line in out.split('\n'):
# This line includes separators, so process them
if SEP in line:
elem = line.split(SEP)
cleaned_elem = []
for e in elem:
e = e.strip()
cleaned_elem.append(e)
if len(cleaned_elem) > 1:
rc.append(cleaned_elem)
else:
t = line.strip()
if len(t) > 0:
rc.append(t)
return rc
def parse_column_names(out, column_names):
lines = parse(out)
rc = []
for i in range(0, len(lines)):
d = dict(list(zip(column_names, lines[i])))
rc.append(d)
return rc
def options_to_cli_args(options):
rc = []
for k, v in list(dict(options).items()):
if k.startswith("-"):
rc.append(k)
else:
rc.append("--%s" % k)
if v != "":
rc.append(str(v))
return rc
def pv_remove(device, remove_options):
cmd = ['pvremove']
cmd.extend(options_to_cli_args(remove_options))
cmd.append(device)
return call(cmd)
def _tag(operation, what, add, rm, tag_options):
cmd = [operation]
cmd.extend(options_to_cli_args(tag_options))
if isinstance(what, list):
cmd.extend(what)
else:
cmd.append(what)
if add:
cmd.extend(list(chain.from_iterable(('--addtag', x) for x in add)))
if rm:
cmd.extend(list(chain.from_iterable(('--deltag', x) for x in rm)))
return call(cmd, False)
def pv_tag(pv_devices, add, rm, tag_options):
return _tag('pvchange', pv_devices, add, rm, tag_options)
def vg_tag(vg_name, add, rm, tag_options):
return _tag('vgchange', vg_name, add, rm, tag_options)
def lv_tag(lv_name, add, rm, tag_options):
return _tag('lvchange', lv_name, add, rm, tag_options)
def vg_rename(vg, new_name, rename_options):
cmd = ['vgrename']
cmd.extend(options_to_cli_args(rename_options))
cmd.extend([vg, new_name])
return call(cmd)
def vg_remove(vg_name, remove_options):
cmd = ['vgremove']
cmd.extend(options_to_cli_args(remove_options))
cmd.extend(['-f', vg_name])
return call(cmd)
def vg_lv_create(vg_name, create_options, name, size_bytes, pv_dests):
cmd = ['lvcreate']
cmd.extend(options_to_cli_args(create_options))
cmd.extend(['--size', str(size_bytes) + 'B'])
cmd.extend(['--name', name, vg_name])
pv_dest_ranges(cmd, pv_dests)
return call(cmd)
def vg_lv_snapshot(vg_name, snapshot_options, name, size_bytes):
cmd = ['lvcreate']
cmd.extend(options_to_cli_args(snapshot_options))
cmd.extend(["-s"])
if size_bytes != 0:
cmd.extend(['--size', str(size_bytes) + 'B'])
cmd.extend(['--name', name, vg_name])
return call(cmd)
def vg_lv_create_linear(vg_name, create_options, name, size_bytes, thin_pool):
cmd = ['lvcreate']
cmd.extend(options_to_cli_args(create_options))
if not thin_pool:
cmd.extend(['--size', str(size_bytes) + 'B'])
else:
cmd.extend(['--thin', '--size', str(size_bytes) + 'B'])
cmd.extend(['--name', name, vg_name])
return call(cmd)
def vg_lv_create_striped(vg_name, create_options, name, size_bytes,
num_stripes, stripe_size_kb, thin_pool):
cmd = ['lvcreate']
cmd.extend(options_to_cli_args(create_options))
if not thin_pool:
cmd.extend(['--size', str(size_bytes) + 'B'])
else:
cmd.extend(['--thin', '--size', str(size_bytes) + 'B'])
cmd.extend(['--stripes', str(num_stripes)])
if stripe_size_kb != 0:
cmd.extend(['--stripesize', str(stripe_size_kb)])
cmd.extend(['--name', name, vg_name])
return call(cmd)
def _vg_lv_create_raid(vg_name, create_options, name, raid_type, size_bytes,
num_stripes, stripe_size_kb):
cmd = ['lvcreate']
cmd.extend(options_to_cli_args(create_options))
cmd.extend(['--type', raid_type])
cmd.extend(['--size', str(size_bytes) + 'B'])
if num_stripes != 0:
cmd.extend(['--stripes', str(num_stripes)])
if stripe_size_kb != 0:
cmd.extend(['--stripesize', str(stripe_size_kb)])
cmd.extend(['--name', name, vg_name])
return call(cmd)
def vg_lv_create_raid(vg_name, create_options, name, raid_type, size_bytes,
num_stripes, stripe_size_kb):
cmd = ['lvcreate']
cmd.extend(options_to_cli_args(create_options))
return _vg_lv_create_raid(vg_name, create_options, name, raid_type,
size_bytes, num_stripes, stripe_size_kb)
def vg_lv_create_mirror(vg_name, create_options, name, size_bytes, num_copies):
cmd = ['lvcreate']
cmd.extend(options_to_cli_args(create_options))
cmd.extend(['--type', 'mirror'])
cmd.extend(['--mirrors', str(num_copies)])
cmd.extend(['--size', str(size_bytes) + 'B'])
cmd.extend(['--name', name, vg_name])
return call(cmd)
def vg_create_cache_pool(md_full_name, data_full_name, create_options):
cmd = ['lvconvert']
cmd.extend(options_to_cli_args(create_options))
cmd.extend(['--type', 'cache-pool', '--force', '-y',
'--poolmetadata', md_full_name, data_full_name])
return call(cmd)
def vg_create_thin_pool(md_full_name, data_full_name, create_options):
cmd = ['lvconvert']
cmd.extend(options_to_cli_args(create_options))
cmd.extend(['--type', 'thin-pool', '--force', '-y',
'--poolmetadata', md_full_name, data_full_name])
return call(cmd)
def lv_remove(lv_path, remove_options):
cmd = ['lvremove']
cmd.extend(options_to_cli_args(remove_options))
cmd.extend(['-f', lv_path])
return call(cmd)
def lv_rename(lv_path, new_name, rename_options):
cmd = ['lvrename']
cmd.extend(options_to_cli_args(rename_options))
cmd.extend([lv_path, new_name])
return call(cmd)
def lv_resize(lv_full_name, size_change, pv_dests,
resize_options):
cmd = ['lvresize', '--force']
cmd.extend(options_to_cli_args(resize_options))
if size_change < 0:
cmd.append("-L-%dB" % (-size_change))
else:
cmd.append("-L+%dB" % (size_change))
cmd.append(lv_full_name)
pv_dest_ranges(cmd, pv_dests)
return call(cmd)
def lv_lv_create(lv_full_name, create_options, name, size_bytes):
cmd = ['lvcreate']
cmd.extend(options_to_cli_args(create_options))
cmd.extend(['--virtualsize', str(size_bytes) + 'B', '-T'])
cmd.extend(['--name', name, lv_full_name])
return call(cmd)
def lv_cache_lv(cache_pool_full_name, lv_full_name, cache_options):
# lvconvert --type cache --cachepool VG/CachePoolLV VG/OriginLV
cmd = ['lvconvert']
cmd.extend(options_to_cli_args(cache_options))
cmd.extend(['--type', 'cache', '--cachepool',
cache_pool_full_name, lv_full_name])
return call(cmd)
def lv_detach_cache(lv_full_name, detach_options, destroy_cache):
cmd = ['lvconvert']
if destroy_cache:
option = '--uncache'
else:
# Currently fairly dangerous
# see: https://bugzilla.redhat.com/show_bug.cgi?id=1248972
option = '--splitcache'
cmd.extend(options_to_cli_args(detach_options))
# needed to prevent interactive questions
cmd.extend(["--yes", "--force"])
cmd.extend([option, lv_full_name])
return call(cmd)
def pv_retrieve_with_segs(device=None):
d = []
err = ""
out = ""
rc = 0
columns = ['pv_name', 'pv_uuid', 'pv_fmt', 'pv_size', 'pv_free',
'pv_used', 'dev_size', 'pv_mda_size', 'pv_mda_free',
'pv_ba_start', 'pv_ba_size', 'pe_start', 'pv_pe_count',
'pv_pe_alloc_count', 'pv_attr', 'pv_tags', 'vg_name',
'vg_uuid', 'pv_seg_start', 'pvseg_size', 'segtype']
# Lvm has some issues where it returns failure when querying pvs when other
# operations are in process, see:
# https://bugzilla.redhat.com/show_bug.cgi?id=1274085
for i in range(0, 10):
cmd = _dc('pvs', ['-o', ','.join(columns)])
if device:
cmd.extend(device)
rc, out, err = call(cmd)
if rc == 0:
d = parse_column_names(out, columns)
break
else:
time.sleep(0.2)
log_debug("LVM Bug workaround, retrying pvs command...")
if rc != 0:
msg = "We were unable to get pvs to return without error after " \
"trying 10 times, RC=%d, STDERR=(%s), STDOUT=(%s)" % \
(rc, err, out)
log_error(msg)
raise RuntimeError(msg)
return d
def pv_resize(device, size_bytes, create_options):
cmd = ['pvresize']
cmd.extend(options_to_cli_args(create_options))
if size_bytes != 0:
cmd.extend(['--setphysicalvolumesize', str(size_bytes) + 'B'])
cmd.extend([device])
return call(cmd)
def pv_create(create_options, devices):
cmd = ['pvcreate', '-ff']
cmd.extend(options_to_cli_args(create_options))
cmd.extend(devices)
return call(cmd)
def pv_allocatable(device, yes, allocation_options):
yn = 'n'
if yes:
yn = 'y'
cmd = ['pvchange']
cmd.extend(options_to_cli_args(allocation_options))
cmd.extend(['-x', yn, device])
return call(cmd)
def pv_scan(activate, cache, device_paths, major_minors, scan_options):
cmd = ['pvscan']
cmd.extend(options_to_cli_args(scan_options))
if activate:
cmd.extend(['--activate', "ay"])
if cache:
cmd.append('--cache')
if len(device_paths) > 0:
for d in device_paths:
cmd.append(d)
if len(major_minors) > 0:
for mm in major_minors:
cmd.append("%s:%s" % (mm))
return call(cmd)
def vg_create(create_options, pv_devices, name):
cmd = ['vgcreate']
cmd.extend(options_to_cli_args(create_options))
cmd.append(name)
cmd.extend(pv_devices)
return call(cmd)
def vg_change(change_options, name):
cmd = ['vgchange']
cmd.extend(options_to_cli_args(change_options))
cmd.append(name)
return call(cmd)
def vg_reduce(vg_name, missing, pv_devices, reduce_options):
cmd = ['vgreduce']
cmd.extend(options_to_cli_args(reduce_options))
if len(pv_devices) == 0:
cmd.append('--all')
if missing:
cmd.append('--removemissing')
cmd.append(vg_name)
cmd.extend(pv_devices)
return call(cmd)
def vg_extend(vg_name, extend_devices, extend_options):
cmd = ['vgextend']
cmd.extend(options_to_cli_args(extend_options))
cmd.append(vg_name)
cmd.extend(extend_devices)
return call(cmd)
def _vg_value_set(name, arguments, options):
cmd = ['vgchange']
cmd.extend(options_to_cli_args(options))
cmd.append(name)
cmd.extend(arguments)
return call(cmd)
def vg_allocation_policy(vg_name, policy, policy_options):
return _vg_value_set(vg_name, ['--alloc', policy], policy_options)
def vg_max_pv(vg_name, number, max_options):
return _vg_value_set(vg_name, ['--maxphysicalvolumes', str(number)],
max_options)
def vg_max_lv(vg_name, number, max_options):
return _vg_value_set(vg_name, ['-l', str(number)], max_options)
def vg_uuid_gen(vg_name, ignore, options):
assert ignore is None
return _vg_value_set(vg_name, ['--uuid'], options)
def activate_deactivate(op, name, activate, control_flags, options):
cmd = [op]
cmd.extend(options_to_cli_args(options))
op = '-a'
if control_flags:
# Autoactivation
if (1 << 0) & control_flags:
op += 'a'
# Exclusive locking (Cluster)
if (1 << 1) & control_flags:
op += 'e'
# Local node activation
if (1 << 2) & control_flags:
op += 'l'
# Activation modes
if (1 << 3) & control_flags:
cmd.extend(['--activationmode', 'complete'])
elif (1 << 4) & control_flags:
cmd.extend(['--activationmode', 'partial'])
# Ignore activation skip
if (1 << 5) & control_flags:
cmd.append('--ignoreactivationskip')
if activate:
op += 'y'
else:
op += 'n'
cmd.append(op)
cmd.append(name)
return call(cmd)
def vg_retrieve(vg_specific):
if vg_specific:
assert isinstance(vg_specific, list)
columns = ['vg_name', 'vg_uuid', 'vg_fmt', 'vg_size', 'vg_free',
'vg_sysid', 'vg_extent_size', 'vg_extent_count',
'vg_free_count', 'vg_profile', 'max_lv', 'max_pv',
'pv_count', 'lv_count', 'snap_count', 'vg_seqno',
'vg_mda_count', 'vg_mda_free', 'vg_mda_size',
'vg_mda_used_count', 'vg_attr', 'vg_tags']
cmd = _dc('vgs', ['-o', ','.join(columns)])
if vg_specific:
cmd.extend(vg_specific)
d = []
rc, out, err = call(cmd)
if rc == 0:
d = parse_column_names(out, columns)
return d
def lv_retrieve_with_segments():
columns = ['lv_uuid', 'lv_name', 'lv_path', 'lv_size',
'vg_name', 'pool_lv_uuid', 'pool_lv', 'origin_uuid',
'origin', 'data_percent',
'lv_attr', 'lv_tags', 'vg_uuid', 'lv_active', 'data_lv',
'metadata_lv', 'seg_pe_ranges', 'segtype', 'lv_parent',
'lv_role', 'lv_layout']
cmd = _dc('lvs', ['-a', '-o', ','.join(columns)])
rc, out, err = call(cmd)
d = []
if rc == 0:
d = parse_column_names(out, columns)
return d
if __name__ == '__main__':
pv_data = pv_retrieve_with_segs()
for p in pv_data:
log_debug(str(p))

30
daemons/lvmdbusd/fetch.py Normal file
View File

@ -0,0 +1,30 @@
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from .pv import load_pvs
from .vg import load_vgs
from .lv import load_lvs
from . import cfg
def load(refresh=True, emit_signal=True, cache_refresh=True, log=True):
num_total_changes = 0
# Go through and load all the PVs, VGs and LVs
if cache_refresh:
cfg.db.refresh(log)
num_total_changes += load_pvs(refresh=refresh, emit_signal=emit_signal,
cache_refresh=False)[1]
num_total_changes += load_vgs(refresh=refresh, emit_signal=emit_signal,
cache_refresh=False)[1]
num_total_changes += load_lvs(refresh=refresh, emit_signal=emit_signal,
cache_refresh=False)[1]
return num_total_changes

170
daemons/lvmdbusd/job.py Normal file
View File

@ -0,0 +1,170 @@
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from .automatedproperties import AutomatedProperties
from .utils import job_obj_path_generate
from . import cfg
from .cfg import JOB_INTERFACE
import dbus
import threading
# noinspection PyPep8Naming
class JobState(object):
def __init__(self, request):
self.rlock = threading.RLock()
self._percent = 0
self._complete = False
self._request = request
self._cond = threading.Condition(self.rlock)
self._ec = 0
self._stderr = ''
# This is an lvm command that is just taking too long and doesn't
# support background operation
if self._request:
# Faking the percentage when we don't have one
self._percent = 1
@property
def Percent(self):
with self.rlock:
return self._percent
@Percent.setter
def Percent(self, value):
with self.rlock:
self._percent = value
@property
def Complete(self):
with self.rlock:
if self._request:
self._complete = self._request.is_done()
if self._complete:
self._percent = 100
return self._complete
@Complete.setter
def Complete(self, value):
with self.rlock:
self._complete = value
self._cond.notify_all()
@property
def GetError(self):
with self.rlock:
if self.Complete:
if self._request:
(rc, error) = self._request.get_errors()
return (rc, str(error))
else:
return (self._ec, self._stderr)
else:
return (-1, 'Job is not complete!')
def set_result(self, ec, msg):
with self.rlock:
self.Complete = True
self._ec = ec
self._stderr = msg
def dtor(self):
with self.rlock:
self._request = None
def Wait(self, timeout):
try:
with self._cond:
# Check to see if we are done, before we wait
if not self.Complete:
if timeout != -1:
self._cond.wait(timeout)
else:
self._cond.wait()
return self.Complete
except RuntimeError:
return False
@property
def Result(self):
with self.rlock:
if self._request:
return self._request.result()
return '/'
# noinspection PyPep8Naming
class Job(AutomatedProperties):
_Percent_meta = ('y', JOB_INTERFACE)
_Complete_meta = ('b', JOB_INTERFACE)
_Result_meta = ('o', JOB_INTERFACE)
_GetError_meta = ('(is)', JOB_INTERFACE)
def __init__(self, request, job_state=None):
super(Job, self).__init__(job_obj_path_generate())
self.set_interface(JOB_INTERFACE)
if job_state:
self.state = job_state
else:
self.state = JobState(request)
@property
def Percent(self):
return self.state.Percent
@Percent.setter
def Percent(self, value):
self.state.Percent = value
@property
def Complete(self):
return self.state.Complete
@Complete.setter
def Complete(self, value):
self.state.Complete = value
@property
def GetError(self):
return self.state.GetError
def set_result(self, ec, msg):
self.state.set_result(ec, msg)
@dbus.service.method(dbus_interface=JOB_INTERFACE)
def Remove(self):
if self.state.Complete:
cfg.om.remove_object(self, True)
self.state.dtor()
else:
raise dbus.exceptions.DBusException(
JOB_INTERFACE, 'Job is not complete!')
@dbus.service.method(dbus_interface=JOB_INTERFACE,
in_signature='i',
out_signature='b')
def Wait(self, timeout):
return self.state.Wait(timeout)
@property
def Result(self):
return self.state.Result
@property
def lvm_id(self):
return str(id(self))
@property
def Uuid(self):
import uuid
return uuid.uuid1()

View File

@ -0,0 +1,85 @@
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from . import cfg
def _compare_construction(o_state, new_state):
# We need to check to see if the objects would get constructed
# the same
existing_ctor, existing_path = o_state.creation_signature()
new_ctor, new_path = new_state.creation_signature()
# print("%s == %s and %s == %s" % (str(existing_ctor), str(new_ctor),
# str(existing_path), str(new_path)))
return ((existing_ctor == new_ctor) and (existing_path == new_path))
def common(retrieve, o_type, search_keys,
object_path, refresh, emit_signal, cache_refresh):
num_changes = 0
existing_paths = []
rc = []
if search_keys:
assert isinstance(search_keys, list)
if cache_refresh:
cfg.db.refresh()
objects = retrieve(search_keys, cache_refresh=False)
# If we are doing a refresh we need to know what we have in memory, what's
# in lvm and add those that are new and remove those that are gone!
if refresh:
existing_paths = cfg.om.object_paths_by_type(o_type)
for o in objects:
# Assume we need to add this one to dbus, unless we are refreshing
# and it's already present
return_object = True
if refresh:
# We are refreshing all the PVs from LVM, if this one exists
# we need to refresh our state.
dbus_object = cfg.om.get_object_by_uuid_lvm_id(*o.identifiers())
if dbus_object:
del existing_paths[dbus_object.dbus_object_path()]
# If the old object state and new object state wouldn't be
# created with the same path and same object constructor we
# need to remove the old object and construct the new one
# instead!
if not _compare_construction(dbus_object.state, o):
# Remove existing and construct new one
cfg.om.remove_object(dbus_object, emit_signal)
dbus_object = o.create_dbus_object(None)
cfg.om.register_object(dbus_object, emit_signal)
num_changes += 1
else:
num_changes += dbus_object.refresh(object_state=o)
return_object = False
if return_object:
dbus_object = o.create_dbus_object(object_path)
cfg.om.register_object(dbus_object, emit_signal)
rc.append(dbus_object)
object_path = None
if refresh:
for k in list(existing_paths.keys()):
cfg.om.remove_object(cfg.om.get_object_by_path(k), True)
num_changes += 1
num_changes += len(rc)
return rc, num_changes

833
daemons/lvmdbusd/lv.py Normal file
View File

@ -0,0 +1,833 @@
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from .automatedproperties import AutomatedProperties
from . import utils
from .utils import vg_obj_path_generate
import dbus
from . import cmdhandler
from . import cfg
from .cfg import LV_INTERFACE, THIN_POOL_INTERFACE, SNAPSHOT_INTERFACE, \
LV_COMMON_INTERFACE, CACHE_POOL_INTERFACE, LV_CACHED
from .request import RequestEntry
from .utils import n, n32
from .loader import common
from .state import State
from . import background
from .utils import round_size
# noinspection PyUnusedLocal
def lvs_state_retrieve(selection, cache_refresh=True):
rc = []
if cache_refresh:
cfg.db.refresh()
for l in cfg.db.fetch_lvs(selection):
rc.append(LvState(
l['lv_uuid'], l['lv_name'],
l['lv_path'], n(l['lv_size']),
l['vg_name'],
l['vg_uuid'], l['pool_lv_uuid'],
l['pool_lv'], l['origin_uuid'], l['origin'],
n32(l['data_percent']), l['lv_attr'],
l['lv_tags'], l['lv_active'], l['data_lv'],
l['metadata_lv'], l['segtype'], l['lv_role'],
l['lv_layout']))
return rc
def load_lvs(lv_name=None, object_path=None, refresh=False, emit_signal=False,
cache_refresh=True):
# noinspection PyUnresolvedReferences
return common(
lvs_state_retrieve,
(LvCommon, Lv, LvThinPool, LvSnapShot),
lv_name, object_path, refresh, emit_signal, cache_refresh)
# noinspection PyPep8Naming,PyUnresolvedReferences,PyUnusedLocal
class LvState(State):
@staticmethod
def _pv_devices(uuid):
rc = []
for pv in sorted(cfg.db.lv_contained_pv(uuid)):
(pv_uuid, pv_name, pv_segs) = pv
pv_obj = cfg.om.get_object_path_by_lvm_id(
pv_uuid, pv_name, gen_new=False)
rc.append((pv_obj, pv_segs))
return dbus.Array(rc, signature="(oa(tts))")
def vg_name_lookup(self):
return cfg.om.get_object_by_path(self.Vg).Name
@property
def lvm_id(self):
return "%s/%s" % (self.vg_name_lookup(), self.Name)
def identifiers(self):
return (self.Uuid, self.lvm_id)
def _get_hidden_lv(self):
rc = dbus.Array([], "o")
vg_name = self.vg_name_lookup()
for l in cfg.db.hidden_lvs(self.Uuid):
full_name = "%s/%s" % (vg_name, l[1])
op = cfg.om.get_object_path_by_lvm_id(
l[0], full_name, gen_new=False)
assert op
rc.append(op)
return rc
def __init__(self, Uuid, Name, Path, SizeBytes,
vg_name, vg_uuid, pool_lv_uuid, PoolLv,
origin_uuid, OriginLv, DataPercent, Attr, Tags, active,
data_lv, metadata_lv, segtypes, role, layout):
utils.init_class_from_arguments(self)
# The segtypes is possibly an array with potentially dupes or a single
# value
self._segs = dbus.Array([], signature='s')
if not isinstance(segtypes, list):
self._segs.append(segtypes)
else:
self._segs.extend(set(segtypes))
self.Vg = cfg.om.get_object_path_by_lvm_id(
vg_uuid, vg_name, vg_obj_path_generate)
self.Devices = LvState._pv_devices(self.Uuid)
if PoolLv:
gen = utils.lv_object_path_method(Name, (Attr, layout, role))
self.PoolLv = cfg.om.get_object_path_by_lvm_id(
pool_lv_uuid, '%s/%s' % (vg_name, PoolLv),
gen)
else:
self.PoolLv = '/'
if OriginLv:
self.OriginLv = \
cfg.om.get_object_path_by_lvm_id(
origin_uuid, '%s/%s' % (vg_name, OriginLv),
vg_obj_path_generate)
else:
self.OriginLv = '/'
self.HiddenLvs = self._get_hidden_lv()
@property
def SegType(self):
return self._segs
def _object_path_create(self):
return utils.lv_object_path_method(
self.Name, (self.Attr, self.layout, self.role))
def _object_type_create(self):
if self.Name[0] == '[':
return LvCommon
if self.Attr[0] == 't':
return LvThinPool
elif self.Attr[0] == 'C':
if 'pool' in self.layout:
return LvCachePool
else:
return LvCacheLv
elif self.OriginLv != '/':
return LvSnapShot
else:
return Lv
def create_dbus_object(self, path):
if not path:
path = cfg.om.get_object_path_by_lvm_id(
self.Uuid, self.lvm_id, self._object_path_create())
obj_ctor = self._object_type_create()
return obj_ctor(path, self)
def creation_signature(self):
klass = self._object_type_create()
path_method = self._object_path_create()
return (klass, path_method)
# noinspection PyPep8Naming
@utils.dbus_property(LV_COMMON_INTERFACE, 'Uuid', 's')
@utils.dbus_property(LV_COMMON_INTERFACE, 'Name', 's')
@utils.dbus_property(LV_COMMON_INTERFACE, 'Path', 's')
@utils.dbus_property(LV_COMMON_INTERFACE, 'SizeBytes', 't')
@utils.dbus_property(LV_COMMON_INTERFACE, 'DataPercent', 'u')
@utils.dbus_property(LV_COMMON_INTERFACE, 'SegType', 'as')
@utils.dbus_property(LV_COMMON_INTERFACE, 'Vg', 'o')
@utils.dbus_property(LV_COMMON_INTERFACE, 'OriginLv', 'o')
@utils.dbus_property(LV_COMMON_INTERFACE, 'PoolLv', 'o')
@utils.dbus_property(LV_COMMON_INTERFACE, 'Devices', "a(oa(tts))")
@utils.dbus_property(LV_COMMON_INTERFACE, 'HiddenLvs', "ao")
class LvCommon(AutomatedProperties):
_Tags_meta = ("as", LV_COMMON_INTERFACE)
_IsThinVolume_meta = ("b", LV_COMMON_INTERFACE)
_IsThinPool_meta = ("b", LV_COMMON_INTERFACE)
_Active_meta = ("b", LV_COMMON_INTERFACE)
_VolumeType_meta = ("(ss)", LV_COMMON_INTERFACE)
_Permissions_meta = ("(ss)", LV_COMMON_INTERFACE)
_AllocationPolicy_meta = ("(ss)", LV_COMMON_INTERFACE)
_State_meta = ("(ss)", LV_COMMON_INTERFACE)
_TargetType_meta = ("(ss)", LV_COMMON_INTERFACE)
_Health_meta = ("(ss)", LV_COMMON_INTERFACE)
_FixedMinor_meta = ('b', LV_COMMON_INTERFACE)
_ZeroBlocks_meta = ('b', LV_COMMON_INTERFACE)
_SkipActivation_meta = ('b', LV_COMMON_INTERFACE)
# noinspection PyUnusedLocal,PyPep8Naming
def __init__(self, object_path, object_state):
super(LvCommon, self).__init__(object_path, lvs_state_retrieve)
self.set_interface(LV_COMMON_INTERFACE)
self.state = object_state
@property
def VolumeType(self):
type_map = {'C': 'Cache', 'm': 'mirrored',
'M': 'Mirrored without initial sync', 'o': 'origin',
'O': 'Origin with merging snapshot', 'r': 'raid',
'R': 'Raid without initial sync', 's': 'snapshot',
'S': 'merging Snapshot', 'p': 'pvmove',
'v': 'virtual', 'i': 'mirror or raid image',
'I': 'mirror or raid Image out-of-sync',
'l': 'mirror log device', 'c': 'under conversion',
'V': 'thin Volume', 't': 'thin pool', 'T': 'Thin pool data',
'e': 'raid or pool metadata or pool metadata spare',
'-': 'Unspecified'}
return (self.state.Attr[0], type_map[self.state.Attr[0]])
@property
def Permissions(self):
type_map = {'w': 'writable', 'r': 'read-only',
'R': 'Read-only activation of non-read-only volume',
'-': 'Unspecified'}
return (self.state.Attr[1], type_map[self.state.Attr[1]])
@property
def AllocationPolicy(self):
type_map = {'a': 'anywhere', 'A': 'anywhere locked',
'c': 'contiguous', 'C': 'contiguous locked',
'i': 'inherited', 'I': 'inherited locked',
'l': 'cling', 'L': 'cling locked',
'n': 'normal', 'N': 'normal locked', '-': 'Unspecified'}
return (self.state.Attr[2], type_map[self.state.Attr[2]])
@property
def FixedMinor(self):
return self.state.Attr[3] == 'm'
@property
def State(self):
type_map = {'a': 'active', 's': 'suspended', 'I': 'Invalid snapshot',
'S': 'invalid Suspended snapshot',
'm': 'snapshot merge failed',
'M': 'suspended snapshot (M)erge failed',
'd': 'mapped device present without tables',
'i': 'mapped device present with inactive table',
'X': 'unknown', '-': 'Unspecified'}
return (self.state.Attr[4], type_map[self.state.Attr[4]])
@property
def TargetType(self):
type_map = {'C': 'Cache', 'm': 'mirror', 'r': 'raid',
's': 'snapshot', 't': 'thin', 'u': 'unknown',
'v': 'virtual', '-': 'Unspecified'}
return (self.state.Attr[6], type_map[self.state.Attr[6]])
@property
def ZeroBlocks(self):
return self.state.Attr[7] == 'z'
@property
def Health(self):
type_map = {'p': 'partial', 'r': 'refresh',
'm': 'mismatches', 'w': 'writemostly',
'X': 'X unknown', '-': 'Unspecified'}
return (self.state.Attr[8], type_map[self.state.Attr[8]])
@property
def SkipActivation(self):
return self.state.Attr[9] == 'k'
def vg_name_lookup(self):
return self.state.vg_name_lookup()
def lv_full_name(self):
return "%s/%s" % (self.state.vg_name_lookup(), self.state.Name)
@property
def identifiers(self):
return self.state.identifiers
@property
def Tags(self):
return utils.parse_tags(self.state.Tags)
@property
def lvm_id(self):
return self.state.lvm_id
@property
def IsThinVolume(self):
return self.state.Attr[0] == 'V'
@property
def IsThinPool(self):
return self.state.Attr[0] == 't'
@property
def Active(self):
return self.state.active == "active"
@dbus.service.method(
dbus_interface=LV_COMMON_INTERFACE,
in_signature='ia{sv}',
out_signature='o')
def _Future(self, tmo, open_options):
raise dbus.exceptions.DBusException(LV_COMMON_INTERFACE, 'Do not use!')
# noinspection PyPep8Naming
class Lv(LvCommon):
# noinspection PyUnusedLocal,PyPep8Naming
def __init__(self, object_path, object_state):
super(Lv, self).__init__(object_path, object_state)
self.set_interface(LV_INTERFACE)
self.state = object_state
@staticmethod
def _remove(lv_uuid, lv_name, remove_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
if dbo:
# Remove the LV, if successful then remove from the model
rc, out, err = cmdhandler.lv_remove(lv_name, remove_options)
if rc == 0:
cfg.om.remove_object(dbo, True)
cfg.load()
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(lv_uuid, lv_name))
return '/'
@dbus.service.method(
dbus_interface=LV_INTERFACE,
in_signature='ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def Remove(self, tmo, remove_options, cb, cbe):
r = RequestEntry(
tmo, Lv._remove,
(self.Uuid, self.lvm_id, remove_options),
cb, cbe, False)
cfg.worker_q.put(r)
@staticmethod
def _rename(lv_uuid, lv_name, new_name, rename_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
if dbo:
# Rename the logical volume
rc, out, err = cmdhandler.lv_rename(lv_name, new_name,
rename_options)
if rc == 0:
cfg.load()
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(lv_uuid, lv_name))
return '/'
@dbus.service.method(
dbus_interface=LV_INTERFACE,
in_signature='sia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def Rename(self, name, tmo, rename_options, cb, cbe):
utils.validate_lv_name(LV_INTERFACE, self.vg_name_lookup(), name)
r = RequestEntry(
tmo, Lv._rename,
(self.Uuid, self.lvm_id, name, rename_options),
cb, cbe, False)
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=LV_INTERFACE,
in_signature='o(tt)a(ott)ia{sv}',
out_signature='o')
def Move(self, pv_src_obj, pv_source_range,
pv_dests_and_ranges,
tmo, move_options):
return background.move(
LV_INTERFACE, self.lvm_id, pv_src_obj,
pv_source_range, pv_dests_and_ranges,
move_options, tmo)
@staticmethod
def _snap_shot(lv_uuid, lv_name, name, optional_size,
snapshot_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
if dbo:
# If you specify a size you get a 'thick' snapshot even if
# it is a thin lv
if not dbo.IsThinVolume:
if optional_size == 0:
# TODO: Should we pick a sane default or force user to
# make a decision?
space = dbo.SizeBytes / 80
remainder = space % 512
optional_size = space + 512 - remainder
rc, out, err = cmdhandler.vg_lv_snapshot(
lv_name, snapshot_options, name, optional_size)
if rc == 0:
return_path = '/'
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
lvs = load_lvs([full_name], emit_signal=True)[0]
for l in lvs:
return_path = l.dbus_object_path()
# Refresh self and all included PVs
cfg.load(cache_refresh=False)
return return_path
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(lv_uuid, lv_name))
@dbus.service.method(
dbus_interface=LV_INTERFACE,
in_signature='stia{sv}',
out_signature='(oo)',
async_callbacks=('cb', 'cbe'))
def Snapshot(self, name, optional_size, tmo,
snapshot_options, cb, cbe):
utils.validate_lv_name(LV_INTERFACE, self.vg_name_lookup(), name)
r = RequestEntry(
tmo, Lv._snap_shot,
(self.Uuid, self.lvm_id, name,
optional_size, snapshot_options), cb, cbe)
cfg.worker_q.put(r)
@staticmethod
def _resize(lv_uuid, lv_name, new_size_bytes, pv_dests_and_ranges,
resize_options):
# Make sure we have a dbus object representing it
pv_dests = []
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
if dbo:
# If we have PVs, verify them
if len(pv_dests_and_ranges):
for pr in pv_dests_and_ranges:
pv_dbus_obj = cfg.om.get_object_by_path(pr[0])
if not pv_dbus_obj:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'PV Destination (%s) not found' % pr[0])
pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
size_change = new_size_bytes - dbo.SizeBytes
rc, out, err = cmdhandler.lv_resize(dbo.lvm_id, size_change,
pv_dests, resize_options)
if rc == 0:
# Refresh what's changed
cfg.load()
return "/"
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(lv_uuid, lv_name))
@dbus.service.method(
dbus_interface=LV_INTERFACE,
in_signature='ta(ott)ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def Resize(self, new_size_bytes, pv_dests_and_ranges, tmo,
resize_options, cb, cbe):
"""
Resize a LV
:param new_size_bytes: The requested final size in bytes
:param pv_dests_and_ranges: An array of pv object paths and src &
dst. segment ranges
:param tmo: -1 to wait forever, 0 to return job immediately, else
number of seconds to wait for operation to complete
before getting a job
:param resize_options: key/value hash of options
:param cb: Used by framework not client facing API
:param cbe: Used by framework not client facing API
:return: '/' if complete, else job object path
"""
r = RequestEntry(
tmo, Lv._resize,
(self.Uuid, self.lvm_id, round_size(new_size_bytes),
pv_dests_and_ranges,
resize_options), cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
@staticmethod
def _lv_activate_deactivate(uuid, lv_name, activate, control_flags,
options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, lv_name)
if dbo:
rc, out, err = cmdhandler.activate_deactivate(
'lvchange', lv_name, activate, control_flags, options)
if rc == 0:
dbo.refresh()
return '/'
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(uuid, lv_name))
@dbus.service.method(
dbus_interface=LV_INTERFACE,
in_signature='tia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def Activate(self, control_flags, tmo, activate_options, cb, cbe):
r = RequestEntry(
tmo, Lv._lv_activate_deactivate,
(self.state.Uuid, self.state.lvm_id, True,
control_flags, activate_options),
cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
# noinspection PyProtectedMember
@dbus.service.method(
dbus_interface=LV_INTERFACE,
in_signature='tia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def Deactivate(self, control_flags, tmo, activate_options, cb, cbe):
r = RequestEntry(
tmo, Lv._lv_activate_deactivate,
(self.state.Uuid, self.state.lvm_id, False,
control_flags, activate_options),
cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
@staticmethod
def _add_rm_tags(uuid, lv_name, tags_add, tags_del, tag_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, lv_name)
if dbo:
rc, out, err = cmdhandler.lv_tag(
lv_name, tags_add, tags_del, tag_options)
if rc == 0:
dbo.refresh()
return '/'
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(uuid, lv_name))
@dbus.service.method(
dbus_interface=LV_INTERFACE,
in_signature='asia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def TagsAdd(self, tags, tmo, tag_options, cb, cbe):
for t in tags:
utils.validate_tag(LV_INTERFACE, t)
r = RequestEntry(
tmo, Lv._add_rm_tags,
(self.state.Uuid, self.state.lvm_id,
tags, None, tag_options),
cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=LV_INTERFACE,
in_signature='asia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def TagsDel(self, tags, tmo, tag_options, cb, cbe):
for t in tags:
utils.validate_tag(LV_INTERFACE, t)
r = RequestEntry(
tmo, Lv._add_rm_tags,
(self.state.Uuid, self.state.lvm_id,
None, tags, tag_options),
cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
# noinspection PyPep8Naming
class LvThinPool(Lv):
_DataLv_meta = ("o", THIN_POOL_INTERFACE)
_MetaDataLv_meta = ("o", THIN_POOL_INTERFACE)
def _fetch_hidden(self, name):
# The name is vg/name
full_name = "%s/%s" % (self.vg_name_lookup(), name)
o = cfg.om.get_object_by_lvm_id(full_name)
if o:
return o.dbus_object_path()
return '/'
def _get_data_meta(self):
# Get the data
return (self._fetch_hidden(self.state.data_lv),
self._fetch_hidden(self.state.metadata_lv))
def __init__(self, object_path, object_state):
super(LvThinPool, self).__init__(object_path, object_state)
self.set_interface(THIN_POOL_INTERFACE)
self._data_lv, self._metadata_lv = self._get_data_meta()
@property
def DataLv(self):
return self._data_lv
@property
def MetaDataLv(self):
return self._metadata_lv
@staticmethod
def _lv_create(lv_uuid, lv_name, name, size_bytes, create_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
lv_created = '/'
if dbo:
rc, out, err = cmdhandler.lv_lv_create(
lv_name, create_options, name, size_bytes)
if rc == 0:
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
lvs = load_lvs([full_name], emit_signal=True)[0]
for l in lvs:
lv_created = l.dbus_object_path()
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(lv_uuid, lv_name))
return lv_created
@dbus.service.method(
dbus_interface=THIN_POOL_INTERFACE,
in_signature='stia{sv}',
out_signature='(oo)',
async_callbacks=('cb', 'cbe'))
def LvCreate(self, name, size_bytes, tmo, create_options, cb, cbe):
utils.validate_lv_name(THIN_POOL_INTERFACE, self.vg_name_lookup(), name)
r = RequestEntry(
tmo, LvThinPool._lv_create,
(self.Uuid, self.lvm_id, name,
round_size(size_bytes), create_options), cb, cbe)
cfg.worker_q.put(r)
# noinspection PyPep8Naming
class LvCachePool(Lv):
def __init__(self, object_path, object_state):
super(LvCachePool, self).__init__(object_path, object_state)
self.set_interface(CACHE_POOL_INTERFACE)
@staticmethod
def _cache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
# Make sure we have a dbus object representing cache pool
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
# Make sure we have dbus object representing lv to cache
lv_to_cache = cfg.om.get_object_by_path(lv_object_path)
if dbo and lv_to_cache:
fcn = lv_to_cache.lv_full_name()
rc, out, err = cmdhandler.lv_cache_lv(
dbo.lv_full_name(), fcn, cache_options)
if rc == 0:
# When we cache an LV, the cache pool and the lv that is getting
# cached need to be removed from the object manager and
# re-created as their interfaces have changed!
cfg.om.remove_object(dbo, emit_signal=True)
cfg.om.remove_object(lv_to_cache, emit_signal=True)
cfg.load()
lv_converted = \
cfg.om.get_object_by_lvm_id(fcn).dbus_object_path()
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
msg = ""
if not dbo:
dbo += 'CachePool LV with uuid %s and name %s not present!' % \
(lv_uuid, lv_name)
if not lv_to_cache:
dbo += 'LV to cache with object path %s not present!' % \
(lv_object_path)
raise dbus.exceptions.DBusException(LV_INTERFACE, msg)
return lv_converted
@dbus.service.method(
dbus_interface=CACHE_POOL_INTERFACE,
in_signature='oia{sv}',
out_signature='(oo)',
async_callbacks=('cb', 'cbe'))
def CacheLv(self, lv_object, tmo, cache_options, cb, cbe):
r = RequestEntry(
tmo, LvCachePool._cache_lv,
(self.Uuid, self.lvm_id, lv_object,
cache_options), cb, cbe)
cfg.worker_q.put(r)
# noinspection PyPep8Naming
class LvCacheLv(Lv):
_CachePool_meta = ("o", LV_CACHED)
def __init__(self, object_path, object_state):
super(LvCacheLv, self).__init__(object_path, object_state)
self.set_interface(LV_CACHED)
@property
def CachePool(self):
return self.state.PoolLv
@staticmethod
def _detach_lv(lv_uuid, lv_name, detach_options, destroy_cache):
# Make sure we have a dbus object representing cache pool
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
if dbo:
# Get current cache name
cache_pool = cfg.om.get_object_by_path(dbo.CachePool)
rc, out, err = cmdhandler.lv_detach_cache(
dbo.lv_full_name(), detach_options, destroy_cache)
if rc == 0:
# The cache pool gets removed as hidden and put back to
# visible, so lets delete
cfg.om.remove_object(cache_pool, emit_signal=True)
cfg.om.remove_object(dbo, emit_signal=True)
cfg.load()
uncached_lv_path = \
cfg.om.get_object_by_lvm_id(lv_name).dbus_object_path()
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(lv_uuid, lv_name))
return uncached_lv_path
@dbus.service.method(
dbus_interface=LV_CACHED,
in_signature='bia{sv}',
out_signature='(oo)',
async_callbacks=('cb', 'cbe'))
def DetachCachePool(self, destroy_cache, tmo, detach_options, cb, cbe):
r = RequestEntry(
tmo, LvCacheLv._detach_lv,
(self.Uuid, self.lvm_id, detach_options,
destroy_cache), cb, cbe)
cfg.worker_q.put(r)
# noinspection PyPep8Naming
class LvSnapShot(Lv):
def __init__(self, object_path, object_state):
super(LvSnapShot, self).__init__(object_path, object_state)
self.set_interface(SNAPSHOT_INTERFACE)
@dbus.service.method(
dbus_interface=SNAPSHOT_INTERFACE,
in_signature='ia{sv}',
out_signature='o')
def Merge(self, tmo, merge_options):
return background.merge(SNAPSHOT_INTERFACE, self.Uuid, self.lvm_id,
merge_options, tmo)

View File

@ -0,0 +1,184 @@
#!/usr/bin/env python3
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Copyright 2015-2016, Vratislav Podzimek <vpodzime@redhat.com>
import subprocess
import shlex
from fcntl import fcntl, F_GETFL, F_SETFL
from os import O_NONBLOCK
import traceback
import sys
import re
try:
from .cfg import LVM_CMD
from .utils import log_debug, log_error
except:
from cfg import LVM_CMD
from utils import log_debug, log_error
SHELL_PROMPT = "lvm> "
def _quote_arg(arg):
if len(shlex.split(arg)) > 1:
return '"%s"' % arg
else:
return arg
class LVMShellProxy(object):
def _read_until_prompt(self):
prev_ec = None
stdout = ""
while not stdout.endswith(SHELL_PROMPT):
try:
tmp = self.lvm_shell.stdout.read()
if tmp:
stdout += tmp.decode("utf-8")
except IOError:
# nothing written yet
pass
# strip the prompt from the STDOUT before returning and grab the exit
# code if it's available
m = self.re.match(stdout)
if m:
prev_ec = int(m.group(2))
strip_idx = -1 * len(m.group(1))
else:
strip_idx = -1 * len(SHELL_PROMPT)
return stdout[:strip_idx], prev_ec
def _read_line(self):
while True:
try:
tmp = self.lvm_shell.stdout.readline()
if tmp:
return tmp.decode("utf-8")
except IOError:
pass
def _discard_echo(self, expected):
line = ""
while line != expected:
# GNU readline inserts some interesting characters at times...
line += self._read_line().replace(' \r', '')
def _write_cmd(self, cmd):
cmd_bytes = bytes(cmd, "utf-8")
num_written = self.lvm_shell.stdin.write(cmd_bytes)
assert (num_written == len(cmd_bytes))
self.lvm_shell.stdin.flush()
def _lvm_echos(self):
echo = False
cmd = "version\n"
self._write_cmd(cmd)
line = self._read_line()
if line == cmd:
echo = True
self._read_until_prompt()
return echo
def __init__(self):
self.re = re.compile(".*(\[(-?[0-9]+)\] lvm> $)", re.DOTALL)
# run the lvm shell
self.lvm_shell = subprocess.Popen(
[LVM_CMD], stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, close_fds=True)
flags = fcntl(self.lvm_shell.stdout, F_GETFL)
fcntl(self.lvm_shell.stdout, F_SETFL, flags | O_NONBLOCK)
flags = fcntl(self.lvm_shell.stderr, F_GETFL)
fcntl(self.lvm_shell.stderr, F_SETFL, flags | O_NONBLOCK)
# wait for the first prompt
self._read_until_prompt()
# Check to see if the version of LVM we are using is running with
# gnu readline which will echo our writes from stdin to stdout
self.echo = self._lvm_echos()
def call_lvm(self, argv, debug=False):
# create the command string
cmd = " ".join(_quote_arg(arg) for arg in argv)
cmd += "\n"
# run the command by writing it to the shell's STDIN
self._write_cmd(cmd)
# If lvm is utilizing gnu readline, it echos stdin to stdout
if self.echo:
self._discard_echo(cmd)
# read everything from the STDOUT to the next prompt
stdout, exit_code = self._read_until_prompt()
# read everything from STDERR if there's something (we waited for the
# prompt on STDOUT so there should be all or nothing at this point on
# STDERR)
stderr = None
try:
t_error = self.lvm_shell.stderr.read()
if t_error:
stderr = t_error.decode("utf-8")
except IOError:
# nothing on STDERR
pass
if exit_code is not None:
rc = exit_code
else:
# LVM does write to stderr even when it did complete successfully,
# so without having the exit code in the prompt we can never be
# sure.
if stderr:
rc = 1
else:
rc = 0
if debug or rc != 0:
log_error(('CMD: %s' % cmd))
log_error(("EC = %d" % rc))
log_error(("STDOUT=\n %s\n" % stdout))
log_error(("STDERR=\n %s\n" % stderr))
return (rc, stdout, stderr)
def __del__(self):
self.lvm_shell.terminate()
if __name__ == "__main__":
shell = LVMShellProxy()
in_line = "start"
try:
while in_line:
in_line = input("lvm> ")
if in_line:
ret, out, err, = shell.call_lvm(in_line.split())
print(("RET: %d" % ret))
print(("OUT:\n%s" % out))
print(("ERR:\n%s" % err))
except KeyboardInterrupt:
pass
except EOFError:
pass
except Exception:
traceback.print_exc(file=sys.stdout)
finally:
print()

411
daemons/lvmdbusd/lvmdb.py Executable file
View File

@ -0,0 +1,411 @@
#!/usr/bin/env python3
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from collections import OrderedDict
import pprint as prettyprint
try:
from . import cmdhandler
from .utils import log_debug
except SystemError:
import cmdhandler
from utils import log_debug
class DataStore(object):
def __init__(self):
self.pvs = {}
self.vgs = {}
self.lvs = {}
self.pv_lvs = {}
self.lv_pvs = {}
self.lvs_hidden = {}
self.pv_path_to_uuid = {}
self.vg_name_to_uuid = {}
self.lv_full_name_to_uuid = {}
self.lvs_in_vgs = {}
self.pvs_in_vgs = {}
# self.refresh()
self.num_refreshes = 0
@staticmethod
def _insert_record(table, key, record, allowed_multiple):
if key in table:
existing = table[key]
for rec_k, rec_v in record.items():
if rec_k in allowed_multiple:
# This column name allows us to store multiple value for
# each type
if not isinstance(existing[rec_k], list):
existing_value = existing[rec_k]
existing[rec_k] = [existing_value, rec_v]
else:
existing[rec_k].append(rec_v)
else:
# If something is not expected to have changing values
# lets ensure that
if existing[rec_k] != rec_v:
raise RuntimeError(
"existing[%s]=%s != %s" %
(rec_k, str(existing[rec_k]),
str(rec_v)))
else:
table[key] = record
@staticmethod
def _parse_pvs(_pvs):
pvs = sorted(_pvs, key=lambda pk: pk['pv_name'])
c_pvs = OrderedDict()
c_lookup = {}
c_pvs_in_vgs = {}
for p in pvs:
DataStore._insert_record(
c_pvs, p['pv_uuid'], p,
['pv_seg_start', 'pvseg_size', 'segtype'])
for p in c_pvs.values():
# Capture which PVs are associated with which VG
if p['vg_uuid'] not in c_pvs_in_vgs:
c_pvs_in_vgs[p['vg_uuid']] = []
if p['vg_name']:
c_pvs_in_vgs[p['vg_uuid']].append(
(p['pv_name'], p['pv_uuid']))
# Lookup for translating between /dev/<name> and pv uuid
c_lookup[p['pv_name']] = p['pv_uuid']
return c_pvs, c_lookup, c_pvs_in_vgs
@staticmethod
def _parse_vgs(_vgs):
vgs = sorted(_vgs, key=lambda vk: vk['vg_name'])
c_vgs = OrderedDict()
c_lookup = {}
for i in vgs:
c_lookup[i['vg_name']] = i['vg_uuid']
DataStore._insert_record(c_vgs, i['vg_uuid'], i, [])
return c_vgs, c_lookup
@staticmethod
def _parse_lvs(_lvs):
lvs = sorted(_lvs, key=lambda vk: vk['lv_name'])
c_lvs = OrderedDict()
c_lvs_in_vgs = {}
c_lvs_hidden = {}
c_lv_full_lookup = {}
for i in lvs:
full_name = "%s/%s" % (i['vg_name'], i['lv_name'])
c_lv_full_lookup[full_name] = i['lv_uuid']
DataStore._insert_record(
c_lvs, i['lv_uuid'], i,
['seg_pe_ranges', 'segtype'])
for i in c_lvs.values():
if i['vg_uuid'] not in c_lvs_in_vgs:
c_lvs_in_vgs[i['vg_uuid']] = []
c_lvs_in_vgs[
i['vg_uuid']].append(
(i['lv_name'],
(i['lv_attr'], i['lv_layout'], i['lv_role']),
i['lv_uuid']))
if i['lv_parent']:
# Lookup what the parent refers too
parent_name = i['lv_parent']
full_parent_name = "%s/%s" % (i['vg_name'], parent_name)
if full_parent_name not in c_lv_full_lookup:
parent_name = '[%s]' % (parent_name)
full_parent_name = "%s/%s" % (i['vg_name'], parent_name)
parent_uuid = c_lv_full_lookup[full_parent_name]
if parent_uuid not in c_lvs_hidden:
c_lvs_hidden[parent_uuid] = []
c_lvs_hidden[parent_uuid].append(
(i['lv_uuid'], i['lv_name']))
return c_lvs, c_lvs_in_vgs, c_lvs_hidden, c_lv_full_lookup
@staticmethod
def _make_list(l):
if not isinstance(l, list):
l = [l]
return l
@staticmethod
def _parse_seg_entry(se, segtype):
if se:
# print("_parse_seg_entry %s %s" % (str(se), str(segtype)))
device, segs = se.split(":")
start, end = segs.split('-')
return (device, (start, end), segtype)
else:
return ("", (), segtype)
@staticmethod
def _build_segments(l, seg_types):
rc = []
l = DataStore._make_list(l)
s = DataStore._make_list(seg_types)
assert len(l) == len(s)
ls = list(zip(l, s))
for i in ls:
if ' ' in i[0]:
tmp = i[0].split(' ')
for t in tmp:
rc.append(DataStore._parse_seg_entry(t, i[1]))
else:
rc.append(DataStore._parse_seg_entry(*i))
return rc
@staticmethod
def _pv_device_lv_entry(table, pv_device, lv_uuid, meta, lv_attr,
segment_info):
if pv_device not in table:
table[pv_device] = {}
if lv_uuid not in table[pv_device]:
table[pv_device][lv_uuid] = {}
table[pv_device][lv_uuid]['segs'] = [segment_info]
table[pv_device][lv_uuid]['name'] = meta
table[pv_device][lv_uuid]['meta'] = lv_attr
else:
table[pv_device][lv_uuid]['segs'].append(segment_info)
@staticmethod
def _pv_device_lv_format(pv_device_lvs):
rc = {}
for pv_device, pd in pv_device_lvs.items():
lvs = []
for lv_uuid, ld in sorted(pd.items()):
lvs.append((lv_uuid, ld['name'], ld['meta'], ld['segs']))
rc[pv_device] = lvs
return rc
@staticmethod
def _lvs_device_pv_entry(table, lv_uuid, pv_device, pv_uuid, segment_info):
if lv_uuid not in table:
table[lv_uuid] = {}
if pv_device not in table[lv_uuid]:
table[lv_uuid][pv_device] = {}
table[lv_uuid][pv_device]['segs'] = [segment_info]
table[lv_uuid][pv_device]['pv_uuid'] = pv_uuid
else:
table[lv_uuid][pv_device]['segs'].append(segment_info)
@staticmethod
def _lvs_device_pv_format(lvs_device_pvs):
rc = {}
for lv_uuid, ld in lvs_device_pvs.items():
pvs = []
for pv_device, pd in sorted(ld.items()):
pvs.append((pd['pv_uuid'], pv_device, pd['segs']))
rc[lv_uuid] = pvs
return rc
def _parse_pv_in_lvs(self):
pv_device_lvs = {} # What LVs are stored on a PV
lvs_device_pv = {} # Where LV data is stored
for i in self.lvs.values():
segs = self._build_segments(i['seg_pe_ranges'], i['segtype'])
for s in segs:
# We are referring to physical device
if '/dev/' in s[0]:
device, r, seg_type = s
DataStore._pv_device_lv_entry(
pv_device_lvs, device, i['lv_uuid'], i['lv_name'],
(i['lv_attr'], i['lv_layout'], i['lv_role']),
(r[0], r[1], seg_type))
# (pv_name, pv_segs, pv_uuid)
DataStore._lvs_device_pv_entry(
lvs_device_pv, i['lv_uuid'], device,
self.pv_path_to_uuid[device], (r[0], r[1], seg_type))
else:
# TODO Handle the case where the segments refer to a LV
# and not a PV
pass
# print("Handle this %s %s %s" % (s[0], s[1], s[2]))
# Convert form to needed result for consumption
pv_device_lvs_result = DataStore._pv_device_lv_format(pv_device_lvs)
lvs_device_pv_result = DataStore._lvs_device_pv_format(lvs_device_pv)
return pv_device_lvs_result, lvs_device_pv_result
def refresh(self, log=True):
"""
Go out and query lvm for the latest data in as few trips as possible
:param log Add debug log entry/exit messages
:return: None
"""
self.num_refreshes += 1
if log:
log_debug("lvmdb - refresh entry")
# Grab everything first then parse it
_raw_pvs = cmdhandler.pv_retrieve_with_segs()
_raw_vgs = cmdhandler.vg_retrieve(None)
_raw_lvs = cmdhandler.lv_retrieve_with_segments()
_pvs, _pvs_lookup, _pvs_in_vgs = self._parse_pvs(_raw_pvs)
_vgs, _vgs_lookup = self._parse_vgs(_raw_vgs)
_lvs, _lvs_in_vgs, _lvs_hidden, _lvs_lookup = self._parse_lvs(_raw_lvs)
# Set all
self.pvs = _pvs
self.pv_path_to_uuid = _pvs_lookup
self.vg_name_to_uuid = _vgs_lookup
self.lv_full_name_to_uuid = _lvs_lookup
self.vgs = _vgs
self.lvs = _lvs
self.lvs_in_vgs = _lvs_in_vgs
self.pvs_in_vgs = _pvs_in_vgs
self.lvs_hidden = _lvs_hidden
# Create lookup table for which LV and segments are on each PV
self.pv_lvs, self.lv_pvs = self._parse_pv_in_lvs()
if log:
log_debug("lvmdb - refresh exit")
def fetch_pvs(self, pv_name):
if not pv_name:
return self.pvs.values()
else:
rc = []
for s in pv_name:
rc.append(self.pvs[self.pv_path_to_uuid[s]])
return rc
def fetch_vgs(self, vg_name):
if not vg_name:
return self.vgs.values()
else:
rc = []
for s in vg_name:
rc.append(self.vgs[self.vg_name_to_uuid[s]])
return rc
def fetch_lvs(self, lv_names):
try:
if not lv_names:
return self.lvs.values()
else:
rc = []
for s in lv_names:
rc.append(self.lvs[self.lv_full_name_to_uuid[s]])
return rc
except KeyError as ke:
print("Key %s not found!" % (str(lv_names)))
print("lv name to uuid lookup")
for keys in sorted(self.lv_full_name_to_uuid.keys()):
print("%s" % (keys))
print("lvs entries by uuid")
for keys in sorted(self.lvs.keys()):
print("%s" % (keys))
raise ke
def pv_pe_segments(self, pv_uuid):
pv = self.pvs[pv_uuid]
return list(zip(pv['pv_seg_start'], pv['pvseg_size']))
def pv_contained_lv(self, pv_device):
rc = []
if pv_device in self.pv_lvs:
rc = self.pv_lvs[pv_device]
return rc
def lv_contained_pv(self, lv_uuid):
rc = []
if lv_uuid in self.lv_pvs:
rc = self.lv_pvs[lv_uuid]
return rc
def lvs_in_vg(self, vg_uuid):
# Return an array of
# (lv_name, (lv_attr, lv_layout, lv_role), lv_uuid)
rc = []
if vg_uuid in self.lvs_in_vgs:
rc = self.lvs_in_vgs[vg_uuid]
return rc
def pvs_in_vg(self, vg_uuid):
# Returns an array of (pv_name, pv_uuid)
rc = []
if vg_uuid in self.pvs_in_vgs:
rc = self.pvs_in_vgs[vg_uuid]
return rc
def hidden_lvs(self, lv_uuid):
# For a specified LV, return a list of hidden lv_uuid, lv_name
# for it
rc = []
if lv_uuid in self.lvs_hidden:
rc = self.lvs_hidden[lv_uuid]
return rc
if __name__ == "__main__":
pp = prettyprint.PrettyPrinter(indent=4)
ds = DataStore()
ds.refresh()
for v in ds.pvs.values():
pp.pprint(v)
for v in ds.vgs.values():
pp.pprint(v)
print("LVS")
for v in ds.lvs.values():
pp.pprint(v)
print("LVS in VG")
for k, v in ds.lvs_in_vgs.items():
print("VG uuid = %s" % (k))
pp.pprint(v)
print("pv_in_lvs")
for k, v in ds.pv_lvs.items():
print("PV %s contains LVS:" % (k))
pp.pprint(v)
for k, v in ds.lv_pvs.items():
print("LV device = %s" % (k))
pp.pprint(v)

16
daemons/lvmdbusd/lvmdbusd Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env python3
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import lvmdbusd
if __name__ == '__main__':
sys.exit(lvmdbusd.main())

176
daemons/lvmdbusd/main.py Normal file
View File

@ -0,0 +1,176 @@
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from . import cfg
from . import objectmanager
from . import utils
from .cfg import BASE_INTERFACE, BASE_OBJ_PATH, MANAGER_OBJ_PATH
import threading
from . import cmdhandler
import time
import signal
import dbus
from . import lvmdb
# noinspection PyUnresolvedReferences
from gi.repository import GObject
from .fetch import load
from .manager import Manager
from .background import background_reaper
import traceback
import queue
from . import udevwatch
from .utils import log_debug
import argparse
import os
from .refresh import handle_external_event, event_complete
class Lvm(objectmanager.ObjectManager):
def __init__(self, object_path):
super(Lvm, self).__init__(object_path, BASE_INTERFACE)
def _discard_pending_refreshes():
# We just handled a refresh, if we have any in the queue they can be
# removed because by definition they are older than the refresh we just did.
# As we limit the number of refreshes getting into the queue
# we should only ever have one to remove.
requests = []
while not cfg.worker_q.empty():
try:
r = cfg.worker_q.get(block=False)
if r.method != handle_external_event:
requests.append(r)
else:
# Make sure we make this event complete even though it didn't
# run, otherwise no other events will get processed
event_complete()
break
except queue.Empty:
break
# Any requests we removed, but did not discard need to be re-queued
for r in requests:
cfg.worker_q.put(r)
def process_request():
while cfg.run.value != 0:
try:
req = cfg.worker_q.get(True, 5)
start = cfg.db.num_refreshes
log_debug(
"Running method: %s with args %s" %
(str(req.method), str(req.arguments)))
req.run_cmd()
end = cfg.db.num_refreshes
num_refreshes = end - start
if num_refreshes > 0:
_discard_pending_refreshes()
if num_refreshes > 1:
log_debug(
"Inspect method %s for too many refreshes" %
(str(req.method)))
log_debug("Complete ")
except queue.Empty:
pass
except Exception:
st = traceback.format_exc()
utils.log_error("process_request exception: \n%s" % st)
def main():
# Add simple command line handling
parser = argparse.ArgumentParser()
parser.add_argument("--udev", action='store_true',
help="Use udev for updating state", default=False,
dest='use_udev')
parser.add_argument("--debug", action='store_true',
help="Dump debug messages", default=False,
dest='debug')
use_session = os.getenv('LVMDBUSD_USE_SESSION', False)
args = parser.parse_args()
cfg.DEBUG = args.debug
# List of threads that we start up
thread_list = []
start = time.time()
# Install signal handlers
for s in [signal.SIGHUP, signal.SIGINT]:
try:
signal.signal(s, utils.handler)
except RuntimeError:
pass
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
GObject.threads_init()
dbus.mainloop.glib.threads_init()
if use_session:
cfg.bus = dbus.SessionBus()
else:
cfg.bus = dbus.SystemBus()
# The base name variable needs to exist for things to work.
# noinspection PyUnusedLocal
base_name = dbus.service.BusName(BASE_INTERFACE, cfg.bus)
cfg.om = Lvm(BASE_OBJ_PATH)
cfg.om.register_object(Manager(MANAGER_OBJ_PATH))
cfg.load = load
cfg.db = lvmdb.DataStore()
# Start up thread to monitor pv moves
thread_list.append(
threading.Thread(target=background_reaper, name="pv_move_reaper"))
# Using a thread to process requests.
thread_list.append(threading.Thread(target=process_request))
cfg.load(refresh=False, emit_signal=False)
cfg.loop = GObject.MainLoop()
for process in thread_list:
process.damon = True
process.start()
end = time.time()
log_debug(
'Service ready! total time= %.2f, lvm time= %.2f count= %d' %
(end - start, cmdhandler.total_time, cmdhandler.total_count),
'bg_black', 'fg_light_green')
# Add udev watching
if args.use_udev:
log_debug('Utilizing udev to trigger updates')
udevwatch.add()
try:
if cfg.run.value != 0:
cfg.loop.run()
if args.use_udev:
udevwatch.remove()
for process in thread_list:
process.join()
except KeyboardInterrupt:
utils.handler(signal.SIGINT, None)
return 0

246
daemons/lvmdbusd/manager.py Normal file
View File

@ -0,0 +1,246 @@
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from .automatedproperties import AutomatedProperties
from . import utils
from .cfg import MANAGER_INTERFACE
import dbus
from . import cfg
from . import cmdhandler
from .fetch import load_pvs, load_vgs
from .request import RequestEntry
from .refresh import event_add
# noinspection PyPep8Naming
class Manager(AutomatedProperties):
_Version_meta = ("t", MANAGER_INTERFACE)
def __init__(self, object_path):
super(Manager, self).__init__(object_path)
self.set_interface(MANAGER_INTERFACE)
@property
def Version(self):
return '1.0.0'
@staticmethod
def _pv_create(device, create_options):
# Check to see if we are already trying to create a PV for an existing
# PV
pv = cfg.om.get_object_path_by_lvm_id(
device, device, None, False)
if pv:
raise dbus.exceptions.DBusException(
MANAGER_INTERFACE, "PV Already exists!")
created_pv = []
rc, out, err = cmdhandler.pv_create(create_options, [device])
if rc == 0:
pvs = load_pvs([device], emit_signal=True)[0]
for p in pvs:
created_pv = p.dbus_object_path()
else:
raise dbus.exceptions.DBusException(
MANAGER_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
return created_pv
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,
in_signature='sia{sv}',
out_signature='(oo)',
async_callbacks=('cb', 'cbe'))
def PvCreate(self, device, tmo, create_options, cb, cbe):
utils.validate_device_path(MANAGER_INTERFACE, device)
r = RequestEntry(
tmo, Manager._pv_create,
(device, create_options), cb, cbe)
cfg.worker_q.put(r)
@staticmethod
def _create_vg(name, pv_object_paths, create_options):
pv_devices = []
for p in pv_object_paths:
pv = cfg.om.get_object_by_path(p)
if pv:
pv_devices.append(pv.Name)
else:
raise dbus.exceptions.DBusException(
MANAGER_INTERFACE, 'object path = %s not found' % p)
rc, out, err = cmdhandler.vg_create(create_options, pv_devices, name)
created_vg = "/"
if rc == 0:
vgs = load_vgs([name], emit_signal=True)[0]
for v in vgs:
created_vg = v.dbus_object_path()
# Update the PVS
load_pvs(refresh=True, emit_signal=True, cache_refresh=False)
else:
raise dbus.exceptions.DBusException(
MANAGER_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
return created_vg
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,
in_signature='saoia{sv}',
out_signature='(oo)',
async_callbacks=('cb', 'cbe'))
def VgCreate(self, name, pv_object_paths, tmo, create_options, cb, cbe):
utils.validate_vg_name(MANAGER_INTERFACE, name)
r = RequestEntry(
tmo, Manager._create_vg,
(name, pv_object_paths, create_options,),
cb, cbe)
cfg.worker_q.put(r)
@staticmethod
def _refresh():
utils.log_debug('Manager.Refresh - entry')
# This is a diagnostic and should not be run in normal operation, so
# lets remove the log entries for refresh as it's implied.
rc = cfg.load(log=False)
if rc != 0:
utils.log_debug('Manager.Refresh - exit %d' % (rc),
'bg_black', 'fg_light_red')
else:
utils.log_debug('Manager.Refresh - exit %d' % (rc))
return rc
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,
out_signature='t',
async_callbacks=('cb', 'cbe'))
def Refresh(self, cb, cbe):
"""
Take all the objects we know about and go out and grab the latest
more of a test method at the moment to make sure we are handling object
paths correctly.
:param cb Callback for result
:param cbe Callback for errors
Returns the number of changes, object add/remove/properties changed
"""
r = RequestEntry(-1, Manager._refresh, (), cb, cbe, False)
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,
in_signature='s',
out_signature='o')
def LookUpByLvmId(self, key):
"""
Given a lvm id in one of the forms:
/dev/sda
some_vg
some_vg/some_lv
Oe1rPX-Pf0W-15E5-n41N-ZmtF-jXS0-Osg8fn
return the object path in O(1) time.
:param key: The lookup value
:return: Return the object path. If object not found you will get '/'
"""
p = cfg.om.get_object_path_by_lvm_id(
key, key, gen_new=False)
if p:
return p
return '/'
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,
in_signature='b')
def UseLvmShell(self, yes_no):
"""
Allow the client to enable/disable lvm shell, used for testing
:param yes_no:
:return: Nothing
"""
cmdhandler.set_execution(yes_no)
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,
in_signature='s', out_signature='i')
def ExternalEvent(self, command):
event_add((command,))
return dbus.Int32(0)
@staticmethod
def _pv_scan(activate, cache, device_path, major_minor, scan_options):
rc, out, err = cmdhandler.pv_scan(
activate, cache, device_path,
major_minor, scan_options)
if rc == 0:
# This could potentially change the state quite a bit, so lets
# update everything to be safe
cfg.load()
return '/'
else:
raise dbus.exceptions.DBusException(
MANAGER_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,
in_signature='bbasa(ii)ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def PvScan(self, activate, cache, device_paths, major_minors,
tmo, scan_options, cb, cbe):
"""
Scan all supported LVM block devices in the system for physical volumes
NOTE: major_minors & device_paths only usable when cache == True
:param activate: If True, activate any newly found LVs
:param cache: If True, update lvmetad
:param device_paths: Array of device paths or empty
:param major_minors: Array of structures (major,minor)
:param tmo: Timeout for operation
:param scan_options: Additional options to pvscan
:param cb: Not visible in API (used for async. callback)
:param cbe: Not visible in API (used for async. error callback)
:return: '/' if operation done, else job path
"""
for d in device_paths:
utils.validate_device_path(MANAGER_INTERFACE, d)
r = RequestEntry(
tmo, Manager._pv_scan,
(activate, cache, device_paths, major_minors,
scan_options), cb, cbe, False)
cfg.worker_q.put(r)
@property
def lvm_id(self):
"""
Intended to be overridden by classes that inherit
"""
return str(id(self))
@property
def Uuid(self):
"""
Intended to be overridden by classes that inherit
"""
import uuid
return uuid.uuid1()

View File

@ -0,0 +1,282 @@
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import threading
import traceback
import dbus
from . import cfg
from .utils import log_debug
from .automatedproperties import AutomatedProperties
# noinspection PyPep8Naming
class ObjectManager(AutomatedProperties):
"""
Implements the org.freedesktop.DBus.ObjectManager interface
"""
def __init__(self, object_path, interface):
super(ObjectManager, self).__init__(object_path, interface)
self.set_interface(interface)
self._ap_o_path = object_path
self._objects = {}
self._id_to_object_path = {}
self.rlock = threading.RLock()
@dbus.service.method(
dbus_interface="org.freedesktop.DBus.ObjectManager",
out_signature='a{oa{sa{sv}}}')
def GetManagedObjects(self):
with self.rlock:
rc = {}
try:
for k, v in list(self._objects.items()):
path, props = v[0].emit_data()
rc[path] = props
except Exception:
traceback.print_exc(file=sys.stdout)
sys.exit(1)
return rc
def locked(self):
"""
If some external code need to run across a number of different
calls into ObjectManager while blocking others they can use this method
to lock others out.
:return:
"""
return ObjectManagerLock(self.rlock)
@dbus.service.signal(
dbus_interface="org.freedesktop.DBus.ObjectManager",
signature='oa{sa{sv}}')
def InterfacesAdded(self, object_path, int_name_prop_dict):
log_debug(
('SIGNAL: InterfacesAdded(%s, %s)' %
(str(object_path), str(int_name_prop_dict))))
@dbus.service.signal(
dbus_interface="org.freedesktop.DBus.ObjectManager",
signature='oas')
def InterfacesRemoved(self, object_path, interface_list):
log_debug(('SIGNAL: InterfacesRemoved(%s, %s)' %
(str(object_path), str(interface_list))))
def _lookup_add(self, obj, path, lvm_id, uuid):
"""
Store information about what we added to the caches so that we
can remove it cleanly
:param obj: The dbus object we are storing
:param lvm_id: The user name for the asset
:param uuid: The uuid for the asset
:return:
"""
# Note: Only called internally, lock implied
# We could have a temp entry from the forward creation of a path
self._lookup_remove(path)
self._objects[path] = (obj, lvm_id, uuid)
self._id_to_object_path[lvm_id] = path
if uuid:
self._id_to_object_path[uuid] = path
def _lookup_remove(self, obj_path):
# Note: Only called internally, lock implied
if obj_path in self._objects:
(obj, lvm_id, uuid) = self._objects[obj_path]
del self._id_to_object_path[lvm_id]
del self._id_to_object_path[uuid]
del self._objects[obj_path]
def lookup_update(self, dbus_obj, new_uuid, new_lvm_id):
with self.rlock:
obj_path = dbus_obj.dbus_object_path()
self._lookup_remove(obj_path)
self._lookup_add(
dbus_obj, obj_path,
new_lvm_id, new_uuid)
def object_paths_by_type(self, o_type):
with self.rlock:
rc = {}
for k, v in list(self._objects.items()):
if isinstance(v[0], o_type):
rc[k] = True
return rc
def register_object(self, dbus_object, emit_signal=False):
"""
Given a dbus object add it to the collection
:param dbus_object: Dbus object to register
:param emit_signal: If true emit a signal for interfaces added
"""
with self.rlock:
path, props = dbus_object.emit_data()
# print 'Registering object path %s for %s' %
# (path, dbus_object.lvm_id)
# We want fast access to the object by a number of different ways
# so we use multiple hashs with different keys
self._lookup_add(dbus_object, path, dbus_object.lvm_id,
dbus_object.Uuid)
if emit_signal:
self.InterfacesAdded(path, props)
def remove_object(self, dbus_object, emit_signal=False):
"""
Given a dbus object, remove it from the collection and remove it
from the dbus framework as well
:param dbus_object: Dbus object to remove
:param emit_signal: If true emit the interfaces removed signal
"""
with self.rlock:
# Store off the object path and the interface first
path = dbus_object.dbus_object_path()
interfaces = dbus_object.interface()
# print 'UN-Registering object path %s for %s' % \
# (path, dbus_object.lvm_id)
self._lookup_remove(path)
# Remove from dbus library
dbus_object.remove_from_connection(cfg.bus, path)
# Optionally emit a signal
if emit_signal:
self.InterfacesRemoved(path, interfaces)
def get_object_by_path(self, path):
"""
Given a dbus path return the object registered for it
:param path: The dbus path
:return: The object
"""
with self.rlock:
if path in self._objects:
return self._objects[path][0]
return None
def get_object_by_uuid_lvm_id(self, uuid, lvm_id):
with self.rlock:
return self.get_object_by_path(
self.get_object_path_by_lvm_id(uuid, lvm_id, None, False))
def get_object_by_lvm_id(self, lvm_id):
"""
Given an lvm identifier, return the object registered for it
:param lvm_id: The lvm identifier
"""
with self.rlock:
if lvm_id in self._id_to_object_path:
return self.get_object_by_path(self._id_to_object_path[lvm_id])
return None
def _uuid_verify(self, path, lvm_id, uuid):
"""
Ensure uuid is present for a successful lvm_id lookup
NOTE: Internal call, assumes under object manager lock
:param path: Path to object we looked up
:param lvm_id: lvm_id used to find object
:param uuid: lvm uuid to verify
:return: None
"""
# This gets called when we found an object based on lvm_id, ensure
# uuid is correct too, as they can change
if lvm_id != uuid:
if uuid not in self._id_to_object_path:
obj = self.get_object_by_path(path)
self._lookup_add(obj, path, lvm_id, uuid)
def get_object_path_by_lvm_id(self, uuid, lvm_id, path_create=None,
gen_new=True):
"""
For a given lvm asset return the dbus object registered to it. If the
object is not found and gen_new == True and path_create is a valid
function we will create a new path, register it and return it.
:param uuid: The uuid for the lvm object
:param lvm_id: The lvm name
:param path_create: If true create an object path if not found
:param gen_new: The function used to create the new path
"""
with self.rlock:
assert lvm_id
assert uuid
if gen_new:
assert path_create
path = None
if lvm_id in self._id_to_object_path:
path = self._id_to_object_path[lvm_id]
self._uuid_verify(path, lvm_id, uuid)
return path
if "/" in lvm_id:
vg, lv = lvm_id.split("/", 1)
int_lvm_id = vg + "/" + ("[%s]" % lv)
if int_lvm_id in self._id_to_object_path:
path = self._id_to_object_path[int_lvm_id]
self._uuid_verify(path, int_lvm_id, uuid)
return path
if uuid and uuid in self._id_to_object_path:
# If we get here it indicates that we found the object, but
# the lvm_id lookup failed. In the case of a rename, the uuid
# will be correct, but the lvm_id will be wrong and vise versa.
# If the lvm_id does not equal the uuid, lets fix up the table
# so that lookups will be handled correctly.
path = self._id_to_object_path[uuid]
# In some cases we are looking up by one or the other, don't
# update when they are the same.
if uuid != lvm_id:
obj = self.get_object_by_path(path)
self._lookup_add(obj, path, lvm_id, uuid)
else:
if gen_new:
path = path_create()
self._lookup_add(None, path, lvm_id, uuid)
# pprint('get_object_path_by_lvm_id(%s, %s, %s, %s: return %s' %
# (uuid, lvm_id, str(path_create), str(gen_new), path))
return path
class ObjectManagerLock(object):
"""
The sole purpose of this class is to allow other code the ability to
lock the object manager using a `with` statement, eg.
with cfg.om.locked():
# Do stuff with object manager
This will ensure that the lock is always released (assuming this is done
correctly)
"""
def __init__(self, recursive_lock):
self._lock = recursive_lock
def __enter__(self):
# Acquire lock
self._lock.acquire()
# noinspection PyUnusedLocal
def __exit__(self, e_type, e_value, e_traceback):
# Release lock
self._lock.release()
self._lock = None

View File

@ -0,0 +1,10 @@
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
LVM_BINARY = "@LVM_PATH@"

282
daemons/lvmdbusd/pv.py Normal file
View File

@ -0,0 +1,282 @@
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from .automatedproperties import AutomatedProperties
from . import utils
from . import cfg
import dbus
from .cfg import PV_INTERFACE
from . import cmdhandler
from .utils import vg_obj_path_generate, n, pv_obj_path_generate, \
lv_object_path_method
from .loader import common
from .request import RequestEntry
from .state import State
from .utils import round_size
# noinspection PyUnusedLocal
def pvs_state_retrieve(selection, cache_refresh=True):
rc = []
if cache_refresh:
cfg.db.refresh()
for p in cfg.db.fetch_pvs(selection):
rc.append(
PvState(
p["pv_name"], p["pv_uuid"], p["pv_name"],
p["pv_fmt"], n(p["pv_size"]), n(p["pv_free"]),
n(p["pv_used"]), n(p["dev_size"]), n(p["pv_mda_size"]),
n(p["pv_mda_free"]), int(p["pv_ba_start"]),
n(p["pv_ba_size"]), n(p["pe_start"]),
int(p["pv_pe_count"]), int(p["pv_pe_alloc_count"]),
p["pv_attr"], p["pv_tags"], p["vg_name"], p["vg_uuid"]))
return rc
def load_pvs(device=None, object_path=None, refresh=False, emit_signal=False,
cache_refresh=True):
return common(
pvs_state_retrieve, (Pv,), device, object_path, refresh,
emit_signal, cache_refresh)
# noinspection PyUnresolvedReferences
class PvState(State):
@property
def lvm_id(self):
return self.lvm_path
def _lv_object_list(self, vg_name):
# Note we are returning "a(oa(tts))"
rc = []
if vg_name:
for lv in sorted(cfg.db.pv_contained_lv(self.lvm_id)):
lv_uuid, lv_name, meta, segs = lv
full_name = "%s/%s" % (vg_name, lv_name)
path_create = lv_object_path_method(lv_name, meta)
lv_path = cfg.om.get_object_path_by_lvm_id(
lv_uuid, full_name, path_create)
rc.append((lv_path, segs))
return dbus.Array(rc, signature="(oa(tts))")
# noinspection PyUnusedLocal,PyPep8Naming
def __init__(self, lvm_path, Uuid, Name,
Fmt, SizeBytes, FreeBytes, UsedBytes, DevSizeBytes,
MdaSizeBytes, MdaFreeBytes, BaStart, BaSizeBytes,
PeStart, PeCount, PeAllocCount, attr, Tags, vg_name,
vg_uuid):
utils.init_class_from_arguments(self)
self.pe_segments = cfg.db.pv_pe_segments(Uuid)
self.lv = self._lv_object_list(vg_name)
if vg_name:
self.vg_path = cfg.om.get_object_path_by_lvm_id(
vg_uuid, vg_name, vg_obj_path_generate)
else:
self.vg_path = '/'
def identifiers(self):
return (self.Uuid, self.lvm_path)
def create_dbus_object(self, path):
if not path:
path = cfg.om.get_object_path_by_lvm_id(self.Uuid, self.Name,
pv_obj_path_generate)
return Pv(path, self)
# noinspection PyMethodMayBeStatic
def creation_signature(self):
return (Pv, pv_obj_path_generate)
# noinspection PyPep8Naming
@utils.dbus_property(PV_INTERFACE, 'Uuid', 's') # PV UUID/pv_uuid
@utils.dbus_property(PV_INTERFACE, 'Name', 's') # PV/pv_name
@utils.dbus_property(PV_INTERFACE, 'Fmt', 's') # Fmt/pv_fmt
@utils.dbus_property(PV_INTERFACE, 'SizeBytes', 't') # PSize/pv_size
@utils.dbus_property(PV_INTERFACE, 'FreeBytes', 't') # PFree/pv_free
@utils.dbus_property(PV_INTERFACE, 'UsedBytes', 't') # Used/pv_used
@utils.dbus_property(PV_INTERFACE, 'DevSizeBytes', 't') # DevSize/dev_size
@utils.dbus_property(PV_INTERFACE, 'MdaSizeBytes', 't') # PMdaSize/pv_mda_size
@utils.dbus_property(PV_INTERFACE, 'MdaFreeBytes', 't') # PMdaFree/pv_mda_free
@utils.dbus_property(PV_INTERFACE, 'BaStart', 't') # BA start/pv_ba_start
@utils.dbus_property(PV_INTERFACE, 'BaSizeBytes', 't') # BA size/pv_ba_size
@utils.dbus_property(PV_INTERFACE, 'PeStart', 't') # 1st PE/pe_start
@utils.dbus_property(PV_INTERFACE, 'PeCount', 't') # PE/pv_pe_count
@utils.dbus_property(PV_INTERFACE, 'PeAllocCount', 't') # PE Allocation count
class Pv(AutomatedProperties):
# For properties that we need custom handlers we need these, otherwise
# we won't get our introspection data
_Tags_meta = ("as", PV_INTERFACE)
_PeSegments_meta = ("a(tt)", PV_INTERFACE)
_Exportable_meta = ("b", PV_INTERFACE)
_Allocatable_meta = ("b", PV_INTERFACE)
_Missing_meta = ("b", PV_INTERFACE)
_Lv_meta = ("a(oa(tts))", PV_INTERFACE)
_Vg_meta = ("o", PV_INTERFACE)
# noinspection PyUnusedLocal,PyPep8Naming
def __init__(self, object_path, state_obj):
super(Pv, self).__init__(object_path, pvs_state_retrieve)
self.set_interface(PV_INTERFACE)
self.state = state_obj
@staticmethod
def _remove(pv_uuid, pv_name, remove_options):
# Remove the PV, if successful then remove from the model
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(pv_uuid, pv_name)
if dbo:
rc, out, err = cmdhandler.pv_remove(pv_name, remove_options)
if rc == 0:
cfg.om.remove_object(dbo, True)
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
PV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
PV_INTERFACE,
'PV with uuid %s and name %s not present!' %
(pv_uuid, pv_name))
return '/'
@dbus.service.method(
dbus_interface=PV_INTERFACE,
in_signature='ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def Remove(self, tmo, remove_options, cb, cbe):
r = RequestEntry(
tmo, Pv._remove,
(self.Uuid, self.lvm_id, remove_options),
cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
@staticmethod
def _resize(pv_uuid, pv_name, new_size_bytes, resize_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(pv_uuid, pv_name)
if dbo:
rc, out, err = cmdhandler.pv_resize(pv_name, new_size_bytes,
resize_options)
if rc == 0:
dbo.refresh()
else:
raise dbus.exceptions.DBusException(
PV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
PV_INTERFACE,
'PV with uuid %s and name %s not present!' %
(pv_uuid, pv_name))
return '/'
@dbus.service.method(
dbus_interface=PV_INTERFACE,
in_signature='tia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def ReSize(self, new_size_bytes, tmo, resize_options, cb, cbe):
r = RequestEntry(
tmo, Pv._resize,
(self.Uuid, self.lvm_id, round_size(new_size_bytes),
resize_options), cb, cbe, False)
cfg.worker_q.put(r)
@staticmethod
def _allocation_enabled(pv_uuid, pv_name, yes_no, allocation_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(pv_uuid, pv_name)
if dbo:
rc, out, err = cmdhandler.pv_allocatable(
pv_name, yes_no, allocation_options)
if rc == 0:
cfg.load()
else:
raise dbus.exceptions.DBusException(
PV_INTERFACE, 'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
PV_INTERFACE,
'PV with uuid %s and name %s not present!' %
(pv_uuid, pv_name))
return '/'
@dbus.service.method(
dbus_interface=PV_INTERFACE,
in_signature='bia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def AllocationEnabled(self, yes, tmo, allocation_options, cb, cbe):
r = RequestEntry(
tmo, Pv._allocation_enabled,
(self.Uuid, self.lvm_id,
yes, allocation_options),
cb, cbe, False)
cfg.worker_q.put(r)
@property
def Tags(self):
return utils.parse_tags(self.state.Tags)
@property
def PeSegments(self):
if len(self.state.pe_segments):
return self.state.pe_segments
return dbus.Array([], '(tt)')
@property
def Exportable(self):
if self.state.attr[1] == 'x':
return True
return False
@property
def Allocatable(self):
if self.state.attr[0] == 'a':
return True
return False
@property
def Missing(self):
if self.state.attr[2] == 'm':
return True
return False
def object_path(self):
return self._object_path
@property
def lvm_id(self):
return self.state.lvm_id
@property
def identifiers(self):
return self.state.identifiers()
@property
def Lv(self):
return self.state.lv
@property
def Vg(self):
return self.state.vg_path

View File

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

140
daemons/lvmdbusd/request.py Normal file
View File

@ -0,0 +1,140 @@
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import threading
# noinspection PyUnresolvedReferences
from gi.repository import GObject
from .job import Job
from . import cfg
import traceback
from .utils import log_error
class RequestEntry(object):
def __init__(self, tmo, method, arguments, cb, cb_error,
return_tuple=True):
self.tmo = tmo
self.method = method
self.arguments = arguments
self.cb = cb
self.cb_error = cb_error
self.timer_id = -1
self.lock = threading.RLock()
self.done = False
self._result = None
self._job = False
self._rc = 0
self._rc_error = None
self._return_tuple = return_tuple
if self.tmo < 0:
# Client is willing to block forever
pass
elif tmo == 0:
self._return_job()
else:
self.timer_id = GObject.timeout_add_seconds(
tmo, RequestEntry._request_timeout, self)
@staticmethod
def _request_timeout(r):
"""
Method which gets called when the timer runs out!
:param r: RequestEntry which timed out
:return: Nothing
"""
r.timer_expired()
def _return_job(self):
self._job = Job(self)
cfg.om.register_object(self._job, True)
if self._return_tuple:
self.cb(('/', self._job.dbus_object_path()))
else:
self.cb(self._job.dbus_object_path())
def run_cmd(self):
try:
result = self.method(*self.arguments)
self.register_result(result)
except Exception:
# Use the request entry to return the result as the client may
# have gotten a job by the time we hit an error
# Lets get the stacktrace and set that to the error message
st = traceback.format_exc()
log_error("Exception returned to client: \n%s" % st)
self.register_error(-1, st)
def is_done(self):
with self.lock:
rc = self.done
return rc
def get_errors(self):
with self.lock:
return (self._rc, self._rc_error)
def result(self):
with self.lock:
if self.done:
return self._result
return '/'
def _reg_ending(self, result, error_rc=0, error=None):
with self.lock:
self.done = True
if self.timer_id != -1:
# Try to prevent the timer from firing
GObject.source_remove(self.timer_id)
self._result = result
self._rc = error_rc
self._rc_error = error
if not self._job:
# We finished and there is no job, so return result or error
# now!
# Note: If we don't have a valid cb or cbe, this indicates a
# request that doesn't need a response as we already returned
# one before the request was processed.
if error_rc == 0:
if self.cb:
if self._return_tuple:
self.cb((result, '/'))
else:
self.cb(result)
else:
if self.cb_error:
self.cb_error(self._rc_error)
else:
# We have a job and it's complete, indicate that it's done.
# TODO: We need to signal the job is done too.
self._job.Complete = True
self._job = None
def register_error(self, error_rc, error):
self._reg_ending(None, error_rc, error)
def register_result(self, result):
self._reg_ending(result)
def timer_expired(self):
with self.lock:
# Set the timer back to -1 as we will get a warning if we try
# to remove a timer that doesn't exist
self.timer_id = -1
if not self.done:
# Create dbus job object and return path to caller
self._return_job()
else:
# The job is done, we have nothing to do
pass
return False

27
daemons/lvmdbusd/state.py Normal file
View File

@ -0,0 +1,27 @@
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from abc import ABCMeta, abstractmethod
class State(object, metaclass=ABCMeta):
@abstractmethod
def lvm_id(self):
pass
@abstractmethod
def identifiers(self):
pass
@abstractmethod
def create_dbus_object(self, path):
pass
def __str__(self):
return '*****\n' + str(self.__dict__) + '\n******\n'

View File

@ -0,0 +1,54 @@
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import pyudev
from .refresh import event_add
from . import cfg
observer = None
# noinspection PyUnusedLocal
def filter_event(action, device):
# Filter for events of interest and add a request object to be processed
# when appropriate.
refresh = False
if '.ID_FS_TYPE_NEW' in device:
fs_type_new = device['.ID_FS_TYPE_NEW']
if 'LVM' in fs_type_new:
refresh = True
elif fs_type_new == '':
# Check to see if the device was one we knew about
if 'DEVNAME' in device:
found = cfg.om.get_object_by_lvm_id(device['DEVNAME'])
if found:
refresh = True
if 'DM_LV_NAME' in device:
refresh = True
if refresh:
event_add(('udev',))
def add():
global observer
context = pyudev.Context()
monitor = pyudev.Monitor.from_netlink(context)
monitor.filter_by('block')
observer = pyudev.MonitorObserver(monitor, filter_event)
observer.start()
def remove():
global observer
observer.stop()
observer = None

484
daemons/lvmdbusd/utils.py Normal file
View File

@ -0,0 +1,484 @@
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import xml.etree.ElementTree as Et
import sys
import inspect
import ctypes
import os
import string
import dbus
import dbus.service
import dbus.mainloop.glib
try:
from . import cfg
except SystemError:
import cfg
STDOUT_TTY = os.isatty(sys.stdout.fileno())
def rtype(dbus_type):
"""
Decorator making sure that the decorated function returns a value of
specified type.
:param dbus_type: The specific dbus type to return value as
"""
def decorator(fn):
def decorated(*args, **kwargs):
return dbus_type(fn(*args, **kwargs))
return decorated
return decorator
# Field is expected to be a number, handle the corner cases when parsing
@rtype(dbus.UInt64)
def n(v):
if not v:
return 0
return int(float(v))
@rtype(dbus.UInt32)
def n32(v):
if not v:
return 0
return int(float(v))
# noinspection PyProtectedMember
def init_class_from_arguments(obj_instance):
for k, v in list(sys._getframe(1).f_locals.items()):
if k != 'self':
nt = k
# If the current attribute has a value, but the incoming does
# not, don't overwrite it. Otherwise the default values on the
# property decorator don't work as expected.
cur = getattr(obj_instance, nt, v)
# print 'Init class %s = %s' % (nt, str(v))
if not (cur and len(str(cur)) and (v is None or len(str(v))) == 0):
setattr(obj_instance, nt, v)
def get_properties(f):
"""
Walks through an object instance or it's parent class(es) and determines
which attributes are properties and if they were created to be used for
dbus.
:param f: Object to inspect
:return: A dictionary of tuples with each tuple being:
0 = An array of dicts with the keys being: p_t, p_name,
p_access(type, name, access)
1 = Hash of property names and current value
"""
interfaces = dict()
for c in inspect.getmro(f.__class__):
h = vars(c)
for p, value in h.items():
if isinstance(value, property):
# We found a property, see if it has a metadata type
key = attribute_type_name(p)
if key in h:
interface = h[key][1]
if interface not in interfaces:
interfaces[interface] = ([], {})
access = ''
if getattr(f.__class__, p).fget:
access += 'read'
if getattr(f.__class__, p).fset:
access += 'write'
interfaces[interface][0].append(
dict(
p_t=getattr(f, key)[0],
p_name=p,
p_access=access))
interfaces[interface][1][p] = getattr(f, p)
return interfaces
def get_object_property_diff(o_prop, n_prop):
"""
Walk through each object properties and report what has changed and with
the new values
:param o_prop: Old keys/values
:param n_prop: New keys/values
:return: hash of properties that have changed and their new value
"""
rc = {}
for intf_k, intf_v in o_prop.items():
for k, v in list(intf_v[1].items()):
# print('Comparing %s:%s to %s:%s' %
# (k, o_prop[intf_k][1][k], k, str(n_prop[intf_k][1][k])))
if o_prop[intf_k][1][k] != n_prop[intf_k][1][k]:
new_value = n_prop[intf_k][1][k]
if intf_k not in rc:
rc[intf_k] = dict()
rc[intf_k][k] = new_value
return rc
def add_properties(xml, interface, props):
"""
Given xml that describes the interface, add property values to the XML
for the specified interface.
:param xml: XML to edit
:param interface: Interface to add the properties too
:param props: Output from get_properties
:return: updated XML string
"""
root = Et.fromstring(xml)
if props:
for c in root:
# print c.attrib['name']
if c.attrib['name'] == interface:
for p in props:
temp = '<property type="%s" name="%s" access="%s"/>\n' % \
(p['p_t'], p['p_name'], p['p_access'])
c.append(Et.fromstring(temp))
return Et.tostring(root, encoding='utf8')
return xml
def attribute_type_name(name):
"""
Given the property name, return string of the attribute type
:param name:
:return:
"""
return "_%s_meta" % name
_type_map = dict(
s=dbus.String,
o=dbus.ObjectPath,
t=dbus.UInt64,
x=dbus.Int64,
u=dbus.UInt32,
i=dbus.Int32,
n=dbus.Int16,
q=dbus.UInt16,
d=dbus.Double,
y=dbus.Byte,
b=dbus.Boolean)
def _pass_through(v):
"""
If we have something which is not a simple type we return the original
value un-wrapped.
:param v:
:return:
"""
return v
def _dbus_type(t, value):
return _type_map.get(t, _pass_through)(value)
def dbus_property(interface_name, name, dbus_type, doc=None):
"""
Creates the get/set properties for the given name. It assumes that the
actual attribute is '_' + name and the attribute metadata is stuffed in
_name_type.
There is probably a better way todo this.
:param interface_name: Dbus interface this property is associated with
:param name: Name of property
:param dbus_type: dbus string type eg. s,t,i,x
:param doc: Python __doc__ for the property
:return:
"""
attribute_name = '_' + name
def getter(self):
t = getattr(self, attribute_name + '_meta')[0]
return _dbus_type(t, getattr(self.state, attribute_name[1:]))
prop = property(getter, None, None, doc)
def decorator(cls):
setattr(cls, attribute_name + '_meta', (dbus_type, interface_name))
setattr(cls, name, prop)
return cls
return decorator
def parse_tags(tags):
if len(tags):
if ',' in tags:
return tags.split(',')
return sorted([tags])
return dbus.Array([], signature='s')
def _common_log(msg, *attributes):
cfg.stdout_lock.acquire()
tid = ctypes.CDLL('libc.so.6').syscall(186)
msg = "%d:%d - %s" % (os.getpid(), tid, msg)
if STDOUT_TTY and attributes:
print(color(msg, *attributes))
else:
print(msg)
cfg.stdout_lock.release()
sys.stdout.flush()
# Serializes access to stdout to prevent interleaved output
# @param msg Message to output to stdout
# @return None
def log_debug(msg, *attributes):
if cfg.DEBUG:
_common_log(msg, *attributes)
def log_error(msg, *attributes):
_common_log(msg, *attributes)
# noinspection PyUnusedLocal
def handler(signum, frame):
cfg.run.value = 0
log_debug('Signal handler called with signal %d' % signum)
if cfg.loop is not None:
cfg.loop.quit()
def pv_obj_path_generate():
return cfg.PV_OBJ_PATH + "/%d" % next(cfg.pv_id)
def vg_obj_path_generate():
return cfg.VG_OBJ_PATH + "/%d" % next(cfg.vg_id)
def lv_object_path_method(name, meta):
if name[0] == '[':
return _hidden_lv_obj_path_generate
elif meta[0][0] == 't':
return _thin_pool_obj_path_generate
elif meta[0][0] == 'C' and 'pool' in meta[1]:
return _cache_pool_obj_path_generate
return _lv_obj_path_generate
# Note: None of the individual LV path generate functions should be called
# directly, they should only be dispatched through lv_object_path_method
def _lv_obj_path_generate():
return cfg.LV_OBJ_PATH + "/%d" % next(cfg.lv_id)
def _thin_pool_obj_path_generate():
return cfg.THIN_POOL_PATH + "/%d" % next(cfg.thin_id)
def _cache_pool_obj_path_generate():
return cfg.CACHE_POOL_PATH + "/%d" % next(cfg.cache_pool_id)
def _hidden_lv_obj_path_generate():
return cfg.HIDDEN_LV_PATH + "/%d" % next(cfg.hidden_lv)
def job_obj_path_generate():
return cfg.JOB_OBJ_PATH + "/%d" % next(cfg.job_id)
def color(text, *user_styles):
styles = {
# styles
'reset': '\033[0m',
'bold': '\033[01m',
'disabled': '\033[02m',
'underline': '\033[04m',
'reverse': '\033[07m',
'strike_through': '\033[09m',
'invisible': '\033[08m',
# text colors
'fg_black': '\033[30m',
'fg_red': '\033[31m',
'fg_green': '\033[32m',
'fg_orange': '\033[33m',
'fg_blue': '\033[34m',
'fg_purple': '\033[35m',
'fg_cyan': '\033[36m',
'fg_light_grey': '\033[37m',
'fg_dark_grey': '\033[90m',
'fg_light_red': '\033[91m',
'fg_light_green': '\033[92m',
'fg_yellow': '\033[93m',
'fg_light_blue': '\033[94m',
'fg_pink': '\033[95m',
'fg_light_cyan': '\033[96m',
# background colors
'bg_black': '\033[40m',
'bg_red': '\033[41m',
'bg_green': '\033[42m',
'bg_orange': '\033[43m',
'bg_blue': '\033[44m',
'bg_purple': '\033[45m',
'bg_cyan': '\033[46m',
'bg_light_grey': '\033[47m'
}
color_text = ''
for style in user_styles:
try:
color_text += styles[style]
except KeyError:
return 'def color: parameter {} does not exist'.format(style)
color_text += text
return '\033[0m{0}\033[0m'.format(color_text)
def pv_range_append(cmd, device, start, end):
if (start, end) == (0, 0):
cmd.append(device)
else:
if start != 0 and end == 0:
cmd.append("%s:%d-" % (device, start))
else:
cmd.append(
"%s:%d-%d" %
(device, start, end))
def pv_dest_ranges(cmd, pv_dest_range_list):
if len(pv_dest_range_list):
for i in pv_dest_range_list:
pv_range_append(cmd, *i)
def round_size(size_bytes):
bs = 512
remainder = size_bytes % bs
if not remainder:
return size_bytes
return size_bytes + bs - remainder
_ALLOWABLE_CH = string.ascii_letters + string.digits + '#+.:=@_\/%'
_ALLOWABLE_CH_SET = set(_ALLOWABLE_CH)
_ALLOWABLE_VG_LV_CH = string.ascii_letters + string.digits + '.-_+'
_ALLOWABLE_VG_LV_CH_SET = set(_ALLOWABLE_VG_LV_CH)
_LV_NAME_RESERVED = ("_cdata", "_cmeta", "_corig", "_mimage", "_mlog",
"_pmspare", "_rimage", "_rmeta", "_tdata", "_tmeta", "_vorigin")
# Tags can have the characters, based on the code
# a-zA-Z0-9._-+/=!:&#
_ALLOWABLE_TAG_CH = string.ascii_letters + string.digits + "._-+/=!:&#"
_ALLOWABLE_TAG_CH_SET = set(_ALLOWABLE_TAG_CH)
def _allowable_tag(tag_name):
# LVM should impose a length restriction
return set(tag_name) <= _ALLOWABLE_TAG_CH_SET
def _allowable_vg_name(vg_name):
if vg_name is None:
raise ValueError("VG name is None or empty")
vg_len = len(vg_name)
if vg_len == 0 or vg_len > 127:
raise ValueError("VG name (%s) length (%d) not in the domain 1..127" %
(vg_name, vg_len))
if not set(vg_name) <= _ALLOWABLE_VG_LV_CH_SET:
raise ValueError("VG name (%s) contains invalid character, "
"allowable set(%s)" % (vg_name, _ALLOWABLE_VG_LV_CH))
if vg_name == "." or vg_name == "..":
raise ValueError('VG name (%s) cannot be "." or ".."' % (vg_name))
def _allowable_lv_name(vg_name, lv_name):
if lv_name is None:
raise ValueError("LV name is None or empty")
lv_len = len(lv_name)
# This length is derived from empirical testing
if lv_len == 0 or (len(vg_name) + lv_len) > 125:
raise ValueError("LV name (%s) length (%d) + VG name length "
"not in the domain 1..125" % (lv_name, lv_len))
if not set(lv_name) <= _ALLOWABLE_VG_LV_CH_SET:
raise ValueError("LV name (%s) contains invalid character, "
"allowable (%s)" % (lv_name, _ALLOWABLE_VG_LV_CH))
if any(x in lv_name for x in _LV_NAME_RESERVED):
raise ValueError("LV name (%s) contains a reserved word, "
"reserved set(%s)" % (lv_name, str(_LV_NAME_RESERVED)))
if lv_name.startswith("snapshot") or lv_name.startswith("pvmove"):
raise ValueError("LV name (%s) starts with a reserved word, "
"reserved set(%s)" % (lv_name, str(["snapshot", "pvmove"])))
if lv_name[0] == '-':
raise ValueError("LV name (%s) cannot start with a '-' "
"character" % lv_name)
def validate_device_path(interface, device):
if not set(device) <= _ALLOWABLE_CH_SET:
raise dbus.exceptions.DBusException(
interface, 'Device path (%s) has invalid characters, '
'allowable (%s)' % (device, _ALLOWABLE_CH))
def validate_vg_name(interface, vg_name):
try:
_allowable_vg_name(vg_name)
except ValueError as ve:
raise dbus.exceptions.DBusException(
interface, str(ve))
def validate_lv_name(interface, vg_name, lv_name):
try:
_allowable_lv_name(vg_name, lv_name)
except ValueError as ve:
raise dbus.exceptions.DBusException(
interface, str(ve))
def validate_tag(interface, tag):
if not _allowable_tag(tag):
raise dbus.exceptions.DBusException(
interface, 'tag (%s) contains invalid character, allowable set(%s)'
% (tag, _ALLOWABLE_TAG_CH))

955
daemons/lvmdbusd/vg.py Normal file
View File

@ -0,0 +1,955 @@
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from .automatedproperties import AutomatedProperties
from . import utils
from .utils import pv_obj_path_generate, vg_obj_path_generate, n
import dbus
from . import cfg
from .cfg import VG_INTERFACE
from . import cmdhandler
from .request import RequestEntry
from .loader import common
from .state import State
from . import background
from .utils import round_size
# noinspection PyUnusedLocal
def vgs_state_retrieve(selection, cache_refresh=True):
rc = []
if cache_refresh:
cfg.db.refresh()
for v in cfg.db.fetch_vgs(selection):
rc.append(
VgState(
v['vg_uuid'], v['vg_name'], v['vg_fmt'], n(v['vg_size']),
n(v['vg_free']), v['vg_sysid'], n(v['vg_extent_size']),
n(v['vg_extent_count']), n(v['vg_free_count']),
v['vg_profile'], n(v['max_lv']), n(v['max_pv']),
n(v['pv_count']), n(v['lv_count']), n(v['snap_count']),
n(v['vg_seqno']), n(v['vg_mda_count']),
n(v['vg_mda_free']), n(v['vg_mda_size']),
n(v['vg_mda_used_count']), v['vg_attr'], v['vg_tags']))
return rc
def load_vgs(vg_specific=None, object_path=None, refresh=False,
emit_signal=False, cache_refresh=True):
return common(vgs_state_retrieve, (Vg,), vg_specific, object_path, refresh,
emit_signal, cache_refresh)
# noinspection PyPep8Naming,PyUnresolvedReferences,PyUnusedLocal
class VgState(State):
@property
def lvm_id(self):
return self.Name
def identifiers(self):
return (self.Uuid, self.Name)
def _lv_paths_build(self):
rc = []
for lv in cfg.db.lvs_in_vg(self.Uuid):
(lv_name, meta, lv_uuid) = lv
full_name = "%s/%s" % (self.Name, lv_name)
gen = utils.lv_object_path_method(lv_name, meta)
lv_path = cfg.om.get_object_path_by_lvm_id(
lv_uuid, full_name, gen)
rc.append(lv_path)
return dbus.Array(rc, signature='o')
def _pv_paths_build(self):
rc = []
for p in cfg.db.pvs_in_vg(self.Uuid):
(pv_name, pv_uuid) = p
rc.append(cfg.om.get_object_path_by_lvm_id(
pv_uuid, pv_name, pv_obj_path_generate))
return dbus.Array(rc, signature='o')
def __init__(self, Uuid, Name, Fmt,
SizeBytes, FreeBytes, SysId, ExtentSizeBytes,
ExtentCount, FreeCount, Profile, MaxLv, MaxPv, PvCount,
LvCount, SnapCount, Seqno, MdaCount, MdaFree,
MdaSizeBytes, MdaUsedCount, attr, tags):
utils.init_class_from_arguments(self)
self.Pvs = self._pv_paths_build()
self.Lvs = self._lv_paths_build()
def create_dbus_object(self, path):
if not path:
path = cfg.om.get_object_path_by_lvm_id(
self.Uuid, self.Name, vg_obj_path_generate)
return Vg(path, self)
# noinspection PyMethodMayBeStatic
def creation_signature(self):
return (Vg, vg_obj_path_generate)
# noinspection PyPep8Naming
@utils.dbus_property(VG_INTERFACE, 'Uuid', 's')
@utils.dbus_property(VG_INTERFACE, 'Name', 's')
@utils.dbus_property(VG_INTERFACE, 'Fmt', 's')
@utils.dbus_property(VG_INTERFACE, 'SizeBytes', 't', 0)
@utils.dbus_property(VG_INTERFACE, 'FreeBytes', 't', 0)
@utils.dbus_property(VG_INTERFACE, 'SysId', 's')
@utils.dbus_property(VG_INTERFACE, 'ExtentSizeBytes', 't')
@utils.dbus_property(VG_INTERFACE, 'ExtentCount', 't')
@utils.dbus_property(VG_INTERFACE, 'FreeCount', 't')
@utils.dbus_property(VG_INTERFACE, 'Profile', 's')
@utils.dbus_property(VG_INTERFACE, 'MaxLv', 't')
@utils.dbus_property(VG_INTERFACE, 'MaxPv', 't')
@utils.dbus_property(VG_INTERFACE, 'PvCount', 't')
@utils.dbus_property(VG_INTERFACE, 'LvCount', 't')
@utils.dbus_property(VG_INTERFACE, 'SnapCount', 't')
@utils.dbus_property(VG_INTERFACE, 'Seqno', 't')
@utils.dbus_property(VG_INTERFACE, 'MdaCount', 't')
@utils.dbus_property(VG_INTERFACE, 'MdaFree', 't')
@utils.dbus_property(VG_INTERFACE, 'MdaSizeBytes', 't')
@utils.dbus_property(VG_INTERFACE, 'MdaUsedCount', 't')
class Vg(AutomatedProperties):
_Tags_meta = ("as", VG_INTERFACE)
_Pvs_meta = ("ao", VG_INTERFACE)
_Lvs_meta = ("ao", VG_INTERFACE)
_Writeable_meta = ("b", VG_INTERFACE)
_Readable_meta = ("b", VG_INTERFACE)
_Resizeable_meta = ("b", VG_INTERFACE)
_Exportable_meta = ('b', VG_INTERFACE)
_Partial_meta = ('b', VG_INTERFACE)
_AllocContiguous_meta = ('b', VG_INTERFACE)
_AllocCling_meta = ('b', VG_INTERFACE)
_AllocNormal_meta = ('b', VG_INTERFACE)
_AllocAnywhere_meta = ('b', VG_INTERFACE)
_Clustered_meta = ('b', VG_INTERFACE)
# noinspection PyUnusedLocal,PyPep8Naming
def __init__(self, object_path, object_state):
super(Vg, self).__init__(object_path, vgs_state_retrieve)
self.set_interface(VG_INTERFACE)
self._object_path = object_path
self.state = object_state
@staticmethod
def fetch_new_lv(vg_name, lv_name):
full_name = "%s/%s" % (vg_name, lv_name)
cfg.load()
l = cfg.om.get_object_by_lvm_id(full_name)
created_lv = l.dbus_object_path()
return created_lv
@staticmethod
def _rename(uuid, vg_name, new_name, rename_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.vg_rename(vg_name, new_name,
rename_options)
if rc == 0:
cfg.load()
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return '/'
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='sia{sv}', out_signature='o',
async_callbacks=('cb', 'cbe'))
def Rename(self, name, tmo, rename_options, cb, cbe):
utils.validate_vg_name(VG_INTERFACE, name)
r = RequestEntry(tmo, Vg._rename,
(self.state.Uuid, self.state.lvm_id, name,
rename_options), cb, cbe, False)
cfg.worker_q.put(r)
@staticmethod
def _remove(uuid, vg_name, remove_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
# Remove the VG, if successful then remove from the model
rc, out, err = cmdhandler.vg_remove(vg_name, remove_options)
if rc == 0:
# Remove the VG
cfg.om.remove_object(dbo, True)
# If an LV has hidden LVs, things can get quite involved,
# especially if it's the last thin pool to get removed, so
# lets refresh all
cfg.load()
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return '/'
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='ia{sv}', out_signature='o',
async_callbacks=('cb', 'cbe'))
def Remove(self, tmo, remove_options, cb, cbe):
r = RequestEntry(tmo, Vg._remove,
(self.state.Uuid, self.state.lvm_id, remove_options),
cb, cbe, False)
cfg.worker_q.put(r)
@staticmethod
def _change(uuid, vg_name, change_options):
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.vg_change(change_options, vg_name)
# To use an example with d-feet (Method input)
# {"activate": __import__('gi.repository.GLib', globals(),
# locals(), ['Variant']).Variant("s", "n")}
if rc == 0:
cfg.load()
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return '/'
# TODO: This should be broken into a number of different methods
# instead of having one method that takes a hash for parameters. Some of
# the changes that vgchange does works on entire system, not just a
# specfic vg, thus that should be in the Manager interface.
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def Change(self, tmo, change_options, cb, cbe):
r = RequestEntry(tmo, Vg._change,
(self.state.Uuid, self.state.lvm_id, change_options),
cb, cbe, False)
cfg.worker_q.put(r)
@staticmethod
def _reduce(uuid, vg_name, missing, pv_object_paths, reduce_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
pv_devices = []
# If pv_object_paths is not empty, then get the device paths
if pv_object_paths and len(pv_object_paths) > 0:
for pv_op in pv_object_paths:
pv = cfg.om.get_object_by_path(pv_op)
if pv:
pv_devices.append(pv.lvm_id)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'PV Object path not found = %s!' % pv_op)
rc, out, err = cmdhandler.vg_reduce(vg_name, missing, pv_devices,
reduce_options)
if rc == 0:
cfg.load()
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE, 'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return '/'
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='baoia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def Reduce(self, missing, pv_object_paths, tmo, reduce_options, cb, cbe):
r = RequestEntry(tmo, Vg._reduce,
(self.state.Uuid, self.state.lvm_id, missing,
pv_object_paths, reduce_options), cb, cbe, False)
cfg.worker_q.put(r)
@staticmethod
def _extend(uuid, vg_name, pv_object_paths, extend_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
extend_devices = []
for i in pv_object_paths:
pv = cfg.om.get_object_by_path(i)
if pv:
extend_devices.append(pv.lvm_id)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE, 'PV Object path not found = %s!' % i)
if len(extend_devices):
rc, out, err = cmdhandler.vg_extend(vg_name, extend_devices,
extend_options)
if rc == 0:
cfg.load()
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE, 'No pv_object_paths provided!')
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return '/'
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='aoia{sv}', out_signature='o',
async_callbacks=('cb', 'cbe'))
def Extend(self, pv_object_paths, tmo, extend_options, cb, cbe):
r = RequestEntry(tmo, Vg._extend,
(self.state.Uuid, self.state.lvm_id, pv_object_paths,
extend_options),
cb, cbe, False)
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='o(tt)a(ott)ia{sv}',
out_signature='o')
def Move(self, pv_src_obj, pv_source_range, pv_dests_and_ranges,
tmo, move_options):
return background.move(
VG_INTERFACE, None, pv_src_obj, pv_source_range,
pv_dests_and_ranges, move_options, tmo)
@staticmethod
def _lv_create(uuid, vg_name, name, size_bytes, pv_dests_and_ranges,
create_options):
# Make sure we have a dbus object representing it
pv_dests = []
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
if len(pv_dests_and_ranges):
for pr in pv_dests_and_ranges:
pv_dbus_obj = cfg.om.get_object_by_path(pr[0])
if not pv_dbus_obj:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'PV Destination (%s) not found' % pr[0])
pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
rc, out, err = cmdhandler.vg_lv_create(
vg_name, create_options, name, size_bytes, pv_dests)
if rc == 0:
return Vg.fetch_new_lv(vg_name, name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='sta(ott)ia{sv}',
out_signature='(oo)',
async_callbacks=('cb', 'cbe'))
def LvCreate(self, name, size_bytes, pv_dests_and_ranges,
tmo, create_options, cb, cbe):
"""
This one it for the advanced users that want to roll their own
:param name: Name of the LV
:param size_bytes: Size of LV in bytes
:param pv_dests_and_ranges: Optional array of PV object paths and
ranges
:param tmo: -1 == Wait forever, 0 == return job immediately, > 0 ==
willing to wait that number of seconds before
getting a job
:param create_options: hash of key/value pairs
:param cb: Internal, not accessible by dbus API user
:param cbe: Internal, not accessible by dbus API user
:return: (oo) First object path is newly created object, second is
job object path if created. Each == '/' when it doesn't
apply.
"""
utils.validate_lv_name(VG_INTERFACE, self.Name, name)
r = RequestEntry(tmo, Vg._lv_create,
(self.state.Uuid, self.state.lvm_id,
name, round_size(size_bytes), pv_dests_and_ranges,
create_options), cb, cbe)
cfg.worker_q.put(r)
@staticmethod
def _lv_create_linear(uuid, vg_name, name, size_bytes,
thin_pool, create_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.vg_lv_create_linear(
vg_name, create_options, name, size_bytes, thin_pool)
if rc == 0:
created_lv = Vg.fetch_new_lv(vg_name, name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return created_lv
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='stbia{sv}',
out_signature='(oo)',
async_callbacks=('cb', 'cbe'))
def LvCreateLinear(self, name, size_bytes,
thin_pool, tmo, create_options, cb, cbe):
utils.validate_lv_name(VG_INTERFACE, self.Name, name)
r = RequestEntry(tmo, Vg._lv_create_linear,
(self.state.Uuid, self.state.lvm_id,
name, round_size(size_bytes), thin_pool,
create_options), cb, cbe)
cfg.worker_q.put(r)
@staticmethod
def _lv_create_striped(uuid, vg_name, name, size_bytes, num_stripes,
stripe_size_kb, thin_pool, create_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.vg_lv_create_striped(
vg_name, create_options, name, size_bytes,
num_stripes, stripe_size_kb, thin_pool)
if rc == 0:
created_lv = Vg.fetch_new_lv(vg_name, name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE, 'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return created_lv
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='stuubia{sv}',
out_signature='(oo)',
async_callbacks=('cb', 'cbe'))
def LvCreateStriped(self, name, size_bytes, num_stripes,
stripe_size_kb, thin_pool, tmo, create_options,
cb, cbe):
utils.validate_lv_name(VG_INTERFACE, self.Name, name)
r = RequestEntry(
tmo, Vg._lv_create_striped,
(self.state.Uuid, self.state.lvm_id, name,
round_size(size_bytes), num_stripes, stripe_size_kb,
thin_pool, create_options),
cb, cbe)
cfg.worker_q.put(r)
@staticmethod
def _lv_create_mirror(uuid, vg_name, name, size_bytes,
num_copies, create_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.vg_lv_create_mirror(
vg_name, create_options, name, size_bytes, num_copies)
if rc == 0:
created_lv = Vg.fetch_new_lv(vg_name, name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return created_lv
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='stuia{sv}',
out_signature='(oo)',
async_callbacks=('cb', 'cbe'))
def LvCreateMirror(self, name, size_bytes, num_copies,
tmo, create_options, cb, cbe):
utils.validate_lv_name(VG_INTERFACE, self.Name, name)
r = RequestEntry(
tmo, Vg._lv_create_mirror,
(self.state.Uuid, self.state.lvm_id, name,
round_size(size_bytes), num_copies,
create_options), cb, cbe)
cfg.worker_q.put(r)
@staticmethod
def _lv_create_raid(uuid, vg_name, name, raid_type, size_bytes,
num_stripes, stripe_size_kb, create_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.vg_lv_create_raid(
vg_name, create_options, name, raid_type, size_bytes,
num_stripes, stripe_size_kb)
if rc == 0:
created_lv = Vg.fetch_new_lv(vg_name, name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return created_lv
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='sstuuia{sv}',
out_signature='(oo)',
async_callbacks=('cb', 'cbe'))
def LvCreateRaid(self, name, raid_type, size_bytes,
num_stripes, stripe_size_kb, tmo,
create_options, cb, cbe):
utils.validate_lv_name(VG_INTERFACE, self.Name, name)
r = RequestEntry(tmo, Vg._lv_create_raid,
(self.state.Uuid, self.state.lvm_id, name,
raid_type, round_size(size_bytes), num_stripes,
stripe_size_kb, create_options), cb, cbe)
cfg.worker_q.put(r)
@staticmethod
def _create_pool(uuid, vg_name, meta_data_lv, data_lv,
create_options, create_method):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
# Retrieve the full names for the metadata and data lv
md = cfg.om.get_object_by_path(meta_data_lv)
data = cfg.om.get_object_by_path(data_lv)
if dbo and md and data:
new_name = data.Name
rc, out, err = create_method(
md.lv_full_name(), data.lv_full_name(), create_options)
if rc == 0:
cfg.om.remove_object(md, emit_signal=True)
cfg.om.remove_object(data, emit_signal=True)
cache_pool_lv = Vg.fetch_new_lv(vg_name, new_name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
msg = ""
if not dbo:
msg += 'VG with uuid %s and name %s not present!' % \
(uuid, vg_name)
if not md:
msg += 'Meta data LV with object path %s not present!' % \
(meta_data_lv)
if not data_lv:
msg += 'Data LV with object path %s not present!' % \
(meta_data_lv)
raise dbus.exceptions.DBusException(VG_INTERFACE, msg)
return cache_pool_lv
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='ooia{sv}',
out_signature='(oo)',
async_callbacks=('cb', 'cbe'))
def CreateCachePool(self, meta_data_lv, data_lv, tmo, create_options,
cb, cbe):
r = RequestEntry(
tmo, Vg._create_pool,
(self.state.Uuid, self.state.lvm_id, meta_data_lv,
data_lv, create_options, cmdhandler.vg_create_cache_pool), cb, cbe)
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='ooia{sv}',
out_signature='(oo)',
async_callbacks=('cb', 'cbe'))
def CreateThinPool(self, meta_data_lv, data_lv, tmo, create_options,
cb, cbe):
r = RequestEntry(
tmo, Vg._create_pool,
(self.state.Uuid, self.state.lvm_id, meta_data_lv,
data_lv, create_options, cmdhandler.vg_create_thin_pool), cb, cbe)
cfg.worker_q.put(r)
@staticmethod
def _pv_add_rm_tags(uuid, vg_name, pv_object_paths, tags_add,
tags_del, tag_options):
pv_devices = []
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
# Check for existence of pv object paths
for p in pv_object_paths:
pv = cfg.om.get_object_by_path(p)
if pv:
pv_devices.append(pv.Name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE, 'PV object path = %s not found' % p)
rc, out, err = cmdhandler.pv_tag(
pv_devices, tags_add, tags_del, tag_options)
if rc == 0:
cfg.load()
return '/'
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='aoasia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def PvTagsAdd(self, pvs, tags, tmo, tag_options, cb, cbe):
for t in tags:
utils.validate_tag(VG_INTERFACE, t)
r = RequestEntry(tmo, Vg._pv_add_rm_tags,
(self.state.Uuid, self.state.lvm_id,
pvs, tags, None, tag_options),
cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='aoasia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def PvTagsDel(self, pvs, tags, tmo, tag_options, cb, cbe):
for t in tags:
utils.validate_tag(VG_INTERFACE, t)
r = RequestEntry(
tmo, Vg._pv_add_rm_tags,
(self.state.Uuid, self.state.lvm_id,
pvs, None, tags, tag_options),
cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
@staticmethod
def _vg_add_rm_tags(uuid, vg_name, tags_add, tags_del, tag_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.vg_tag(
vg_name, tags_add, tags_del, tag_options)
if rc == 0:
dbo.refresh()
return '/'
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='asia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def TagsAdd(self, tags, tmo, tag_options, cb, cbe):
for t in tags:
utils.validate_tag(VG_INTERFACE, t)
r = RequestEntry(tmo, Vg._vg_add_rm_tags,
(self.state.Uuid, self.state.lvm_id,
tags, None, tag_options),
cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='asia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def TagsDel(self, tags, tmo, tag_options, cb, cbe):
for t in tags:
utils.validate_tag(VG_INTERFACE, t)
r = RequestEntry(tmo, Vg._vg_add_rm_tags,
(self.state.Uuid, self.state.lvm_id,
None, tags, tag_options),
cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
@staticmethod
def _vg_change_set(uuid, vg_name, method, value, options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = method(vg_name, value, options)
if rc == 0:
dbo.refresh()
return '/'
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='sia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def AllocationPolicySet(self, policy, tmo, policy_options, cb, cbe):
r = RequestEntry(tmo, Vg._vg_change_set,
(self.state.Uuid, self.state.lvm_id,
cmdhandler.vg_allocation_policy,
policy, policy_options),
cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='tia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def MaxPvSet(self, number, tmo, max_options, cb, cbe):
r = RequestEntry(tmo, Vg._vg_change_set,
(self.state.Uuid, self.state.lvm_id,
cmdhandler.vg_max_pv, number, max_options),
cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def UuidGenerate(self, tmo, options, cb, cbe):
r = RequestEntry(tmo, Vg._vg_change_set,
(self.state.Uuid, self.state.lvm_id,
cmdhandler.vg_uuid_gen, None, options),
cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
def _attribute(self, pos, ch):
if self.state.attr[pos] == ch:
return True
return False
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='tia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def MaxLvSet(self, number, tmo, max_options, cb, cbe):
r = RequestEntry(tmo, Vg._vg_change_set,
(self.state.Uuid, self.state.lvm_id,
cmdhandler.vg_max_lv, number, max_options),
cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
@staticmethod
def _vg_activate_deactivate(uuid, vg_name, activate, control_flags,
options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.activate_deactivate(
'vgchange', vg_name, activate, control_flags, options)
if rc == 0:
cfg.load()
return '/'
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='tia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def Activate(self, control_flags, tmo, activate_options, cb, cbe):
r = RequestEntry(tmo, Vg._vg_activate_deactivate,
(self.state.Uuid, self.state.lvm_id, True,
control_flags, activate_options),
cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='tia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def Deactivate(self, control_flags, tmo, activate_options, cb, cbe):
r = RequestEntry(tmo, Vg._vg_activate_deactivate,
(self.state.Uuid, self.state.lvm_id, False,
control_flags, activate_options),
cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
@property
def Tags(self):
return utils.parse_tags(self.state.tags)
@property
def Pvs(self):
return self.state.Pvs
@property
def Lvs(self):
return self.state.Lvs
@property
def lvm_id(self):
return self.state.lvm_id
@property
def Writeable(self):
return self._attribute(0, 'w')
@property
def Readable(self):
return self._attribute(0, 'r')
@property
def Resizeable(self):
return self._attribute(1, 'z')
@property
def Exportable(self):
return self._attribute(2, 'x')
@property
def Partial(self):
return self._attribute(3, 'p')
@property
def AllocContiguous(self):
return self._attribute(4, 'c')
@property
def AllocCling(self):
return self._attribute(4, 'l')
@property
def AllocNormal(self):
return self._attribute(4, 'n')
@property
def AllocAnywhere(self):
return self._attribute(4, 'a')
@property
def Clustered(self):
return self._attribute(5, 'c')

View File

@ -9,7 +9,7 @@
#
# 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
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@

View File

@ -77,7 +77,7 @@ int main(int argc, char **argv)
val = atoi(argv[2]);
reply = daemon_send_simple(h, "set_global_info",
"global_invalid = %d", val,
"global_invalid = " FMTd64, (int64_t) val,
"token = %s", "skip",
NULL);
print_reply(reply);
@ -106,21 +106,21 @@ int main(int argc, char **argv)
reply = daemon_send_simple(h, "set_vg_info",
"uuid = %s", uuid,
"name = %s", name,
"version = %d", ver,
"token = %s", "skip",
NULL);
"version = " FMTd64, (int64_t) ver,
"token = %s", "skip",
NULL);
} else if (uuid) {
reply = daemon_send_simple(h, "set_vg_info",
"uuid = %s", uuid,
"version = %d", ver,
"token = %s", "skip",
NULL);
"version = " FMTd64, (int64_t) ver,
"token = %s", "skip",
NULL);
} else if (name) {
reply = daemon_send_simple(h, "set_vg_info",
"name = %s", name,
"version = %d", ver,
"token = %s", "skip",
NULL);
"version = " FMTd64, (int64_t) ver,
"token = %s", "skip",
NULL);
} else {
printf("name or uuid required\n");
return -1;

View File

@ -9,7 +9,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _LVM_LVMETAD_CLIENT_H

File diff suppressed because it is too large Load Diff

View File

@ -9,7 +9,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "tool.h"

View File

@ -9,7 +9,7 @@
#
# 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
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@

View File

@ -18,7 +18,6 @@
#include <errno.h>
#include <fcntl.h>
#include <syslog.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/un.h>
@ -456,7 +455,7 @@ static int do_able(const char *req_name)
reply = _lvmlockd_send(req_name,
"cmd = %s", "lvmlockctl",
"pid = %d", getpid(),
"pid = " FMTd64, (int64_t) getpid(),
"vg_name = %s", arg_vg_name,
NULL);
@ -487,7 +486,7 @@ static int do_stop_lockspaces(void)
reply = _lvmlockd_send("stop_all",
"cmd = %s", "lvmlockctl",
"pid = %d", getpid(),
"pid = " FMTd64, (int64_t) getpid(),
"opts = %s", opts[0] ? opts : "none",
NULL);
@ -522,7 +521,7 @@ static int do_kill(void)
reply = _lvmlockd_send("kill_vg",
"cmd = %s", "lvmlockctl",
"pid = %d", getpid(),
"pid = " FMTd64, (int64_t) getpid(),
"vg_name = %s", arg_vg_name,
NULL);
@ -568,7 +567,7 @@ static int do_drop(void)
reply = _lvmlockd_send("drop_vg",
"cmd = %s", "lvmlockctl",
"pid = %d", getpid(),
"pid = " FMTd64, (int64_t) getpid(),
"vg_name = %s", arg_vg_name,
NULL);

View File

@ -16,7 +16,6 @@
#include "daemon-io.h"
#include "daemon-server.h"
#include "daemon-log.h"
#include "lvm-version.h"
#include "lvmetad-client.h"
#include "lvmlockd-client.h"
@ -318,7 +317,7 @@ static void log_save_line(int len, char *line,
unsigned int w = *wrap;
int i;
if (len < LOG_DUMP_SIZE - p) {
if (len < (int) (LOG_DUMP_SIZE - p)) {
memcpy(log_buf + p, line, len);
p += len;
@ -742,24 +741,6 @@ static const char *op_str(int x)
};
}
static const char *mode_str(int x)
{
switch (x) {
case LD_LK_IV:
return "iv";
case LD_LK_UN:
return "un";
case LD_LK_NL:
return "nl";
case LD_LK_SH:
return "sh";
case LD_LK_EX:
return "ex";
default:
return ".";
};
}
int last_string_from_args(char *args_in, char *last)
{
const char *args = args_in;
@ -1021,6 +1002,43 @@ static void add_work_action(struct action *act)
pthread_mutex_unlock(&worker_mutex);
}
static daemon_reply send_lvmetad(const char *id, ...)
{
daemon_reply reply;
va_list ap;
int retries = 0;
va_start(ap, id);
/*
* mutex is used because all threads share a single
* lvmetad connection/handle.
*/
pthread_mutex_lock(&lvmetad_mutex);
retry:
reply = daemon_send_simple_v(lvmetad_handle, id, ap);
/* lvmetad may have been restarted */
if ((reply.error == ECONNRESET) && (retries < 2)) {
daemon_close(lvmetad_handle);
lvmetad_connected = 0;
lvmetad_handle = lvmetad_open(NULL);
if (lvmetad_handle.error || lvmetad_handle.socket_fd < 0) {
log_error("lvmetad_open reconnect error %d", lvmetad_handle.error);
} else {
log_debug("lvmetad reconnected");
lvmetad_connected = 1;
}
retries++;
goto retry;
}
pthread_mutex_unlock(&lvmetad_mutex);
va_end(ap);
return reply;
}
static int res_lock(struct lockspace *ls, struct resource *r, struct action *act, int *retry)
{
struct lock *lk;
@ -1247,14 +1265,12 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
else
uuid = ls->vg_uuid;
pthread_mutex_lock(&lvmetad_mutex);
reply = daemon_send_simple(lvmetad_handle, "set_vg_info",
"token = %s", "skip",
"uuid = %s", uuid,
"name = %s", ls->vg_name,
"version = %d", (int)new_version,
NULL);
pthread_mutex_unlock(&lvmetad_mutex);
reply = send_lvmetad("set_vg_info",
"token = %s", "skip",
"uuid = %s", uuid,
"name = %s", ls->vg_name,
"version = " FMTd64, (int64_t)new_version,
NULL);
if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK"))
log_error("set_vg_info in lvmetad failed %d", reply.error);
@ -1267,12 +1283,10 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
log_debug("S %s R %s res_lock set lvmetad global invalid",
ls->name, r->name);
pthread_mutex_lock(&lvmetad_mutex);
reply = daemon_send_simple(lvmetad_handle, "set_global_info",
"token = %s", "skip",
"global_invalid = %d", 1,
NULL);
pthread_mutex_unlock(&lvmetad_mutex);
reply = send_lvmetad("set_global_info",
"token = %s", "skip",
"global_invalid = " FMTd64, INT64_C(1),
NULL);
if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK"))
log_error("set_global_info in lvmetad failed %d", reply.error);
@ -1333,7 +1347,7 @@ static int res_convert(struct lockspace *ls, struct resource *r,
r->last_client_id = act->client_id;
log_debug("S %s R %s res_convert cl %u mode %d", ls->name, r->name, act->client_id, act->mode);
log_debug("S %s R %s res_convert cl %u mode %s", ls->name, r->name, act->client_id, mode_str(act->mode));
if (act->mode == LD_LK_EX && lk->mode == LD_LK_SH && r->sh_count > 1)
return -EAGAIN;
@ -1347,12 +1361,16 @@ static int res_convert(struct lockspace *ls, struct resource *r,
r->version++;
lk->version = r->version;
r_version = r->version;
r->version_zero_valid = 0;
log_debug("S %s R %s res_convert r_version inc %u",
ls->name, r->name, r_version);
} else if ((r->type == LD_RT_VG) && (r->mode == LD_LK_EX) && (lk->version > r->version)) {
r->version = lk->version;
r_version = r->version;
r->version_zero_valid = 0;
log_debug("S %s R %s res_convert r_version new %u", ls->name, r->name, r_version);
} else {
r_version = 0;
@ -1547,8 +1565,23 @@ static int res_update(struct lockspace *ls, struct resource *r,
if (act->flags & LD_AF_NEXT_VERSION)
lk->version = r->version + 1;
else
else {
if (r->version >= act->version) {
/*
* This update is done from vg_write. If the metadata with
* this seqno is not committed by vg_commit, then next
* vg_write can use the same seqno, causing us to see no
* increase in seqno here as expected.
* FIXME: In this case, do something like setting the lvb
* version to 0 to instead of the same seqno which will
* force an invalidation on other hosts. The next change
* will return to using the seqno again.
*/
log_error("S %s R %s res_update cl %u old version %u new version %u too small",
ls->name, r->name, act->client_id, r->version, act->version);
}
lk->version = act->version;
}
log_debug("S %s R %s res_update cl %u lk version to %u", ls->name, r->name, act->client_id, lk->version);
@ -2236,6 +2269,7 @@ static void *lockspace_thread_main(void *arg_in)
struct action *act_op_free = NULL;
struct list_head tmp_act;
struct list_head act_close;
char tmp_name[MAX_NAME+1];
int free_vg = 0;
int drop_vg = 0;
int error = 0;
@ -2601,6 +2635,10 @@ out_act:
ls->drop_vg = drop_vg;
if (ls->lm_type == LD_LM_DLM && !strcmp(ls->name, gl_lsname_dlm))
global_dlm_lockspace_exists = 0;
/* Avoid a name collision of the same lockspace is added again before this thread is cleaned up. */
memset(tmp_name, 0, sizeof(tmp_name));
snprintf(tmp_name, MAX_NAME, "REM:%s", ls->name);
memcpy(ls->name, tmp_name, MAX_NAME);
pthread_mutex_unlock(&lockspaces_mutex);
/* worker_thread will join this thread, and free the ls */
@ -3030,6 +3068,7 @@ static int for_each_lockspace(int do_stop, int do_free, int do_force)
int free_count = 0;
int done;
int stop;
int perrno;
pthread_mutex_lock(&lockspaces_mutex);
@ -3072,11 +3111,15 @@ static int for_each_lockspace(int do_stop, int do_free, int do_force)
* thread touches the ls struct under lockspaces_mutex.
*/
if (done) {
pthread_join(ls->thread, NULL);
if ((perrno = pthread_join(ls->thread, NULL)))
log_error("pthread_join error %d", perrno);
list_del(&ls->list);
/* FIXME: will free_vg ever not be set? */
log_debug("free ls %s", ls->name);
if (ls->free_vg) {
/* In future we may need to free ls->actions here */
free_ls_resources(ls);
@ -3329,6 +3372,11 @@ static void *worker_thread_main(void *arg_in)
int run_sanlock = lm_is_running_sanlock();
int run_dlm = lm_is_running_dlm();
if (daemon_test) {
run_sanlock = gl_use_sanlock;
run_dlm = gl_use_dlm;
}
if (run_sanlock && run_dlm)
act->result = -EXFULL;
else if (!run_sanlock && !run_dlm)
@ -3592,12 +3640,15 @@ static int client_send_result(struct client *cl, struct action *act)
strcat(result_flags, "NO_LOCKSPACES,");
pthread_mutex_unlock(&lockspaces_mutex);
if (gl_use_sanlock && !gl_lsname_sanlock[0])
strcat(result_flags, "NO_GL_LS,");
else if (gl_use_dlm && !gl_lsname_dlm[0])
strcat(result_flags, "NO_GL_LS,");
else
if (gl_use_sanlock) {
if (!gl_lsname_sanlock[0])
strcat(result_flags, "NO_GL_LS,");
} else if (gl_use_dlm) {
if (!gl_lsname_dlm[0])
strcat(result_flags, "NO_GL_LS,");
} else {
strcat(result_flags, "NO_GL_LS,");
}
}
if (act->flags & LD_AF_DUP_GL_LS)
@ -3626,9 +3677,9 @@ static int client_send_result(struct client *cl, struct action *act)
act->result, vg_args ? vg_args : "", lv_args ? lv_args : "");
res = daemon_reply_simple("OK",
"op = %d", act->op,
"op_result = %d", act->result,
"lm_result = %d", act->lm_rv,
"op = " FMTd64, (int64_t)act->op,
"op_result = " FMTd64, (int64_t) act->result,
"lm_result = " FMTd64, (int64_t) act->lm_rv,
"vg_lock_args = %s", vg_args,
"lv_lock_args = %s", lv_args,
"result_flags = %s", result_flags[0] ? result_flags : "none",
@ -3657,8 +3708,8 @@ static int client_send_result(struct client *cl, struct action *act)
act->result, dump_len);
res = daemon_reply_simple("OK",
"result = %d", act->result,
"dump_len = %d", dump_len,
"result = " FMTd64, (int64_t) act->result,
"dump_len = " FMTd64, (int64_t) dump_len,
NULL);
} else {
/*
@ -3671,10 +3722,10 @@ static int client_send_result(struct client *cl, struct action *act)
act->result, (act->result == -ENOLS) ? "ENOLS" : "", result_flags);
res = daemon_reply_simple("OK",
"op = %d", act->op,
"op = " FMTd64, (int64_t) act->op,
"lock_type = %s", lm_str(act->lm_type),
"op_result = %d", act->result,
"lm_result = %d", act->lm_rv,
"op_result = " FMTd64, (int64_t) act->result,
"lm_result = " FMTd64, (int64_t) act->lm_rv,
"result_flags = %s", result_flags[0] ? result_flags : "none",
NULL);
}
@ -4401,9 +4452,9 @@ static void client_recv_action(struct client *cl)
buffer_init(&res.buffer);
res = daemon_reply_simple("OK",
"result = %d", result,
"result = " FMTd64, (int64_t) result,
"protocol = %s", lvmlockd_protocol,
"version = %d", lvmlockd_protocol_version,
"version = " FMTd64, (int64_t) lvmlockd_protocol_version,
NULL);
buffer_write(cl->fd, &res.buffer);
buffer_destroy(&res.buffer);
@ -4742,15 +4793,11 @@ static int get_lockd_vgs(struct list_head *vg_lockd)
const char *lock_type;
const char *lock_args;
char find_str_path[PATH_MAX];
int mutex_unlocked = 0;
int rv = 0;
INIT_LIST_HEAD(&update_vgs);
pthread_mutex_lock(&lvmetad_mutex);
reply = daemon_send_simple(lvmetad_handle, "vg_list",
"token = %s", "skip",
NULL);
reply = send_lvmetad("vg_list", "token = %s", "skip", NULL);
if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
log_error("vg_list from lvmetad failed %d", reply.error);
@ -4787,10 +4834,10 @@ static int get_lockd_vgs(struct list_head *vg_lockd)
/* get vg_name and lock_type for each vg uuid entry in update_vgs */
list_for_each_entry(ls, &update_vgs, list) {
reply = daemon_send_simple(lvmetad_handle, "vg_lookup",
"token = %s", "skip",
"uuid = %s", ls->vg_uuid,
NULL);
reply = send_lvmetad("vg_lookup",
"token = %s", "skip",
"uuid = %s", ls->vg_uuid,
NULL);
if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
log_error("vg_lookup from lvmetad failed %d", reply.error);
@ -4879,8 +4926,6 @@ static int get_lockd_vgs(struct list_head *vg_lockd)
if (rv < 0)
break;
}
pthread_mutex_unlock(&lvmetad_mutex);
mutex_unlocked = 1;
out:
/* Return lockd VG's on the vg_lockd list. */
@ -4893,9 +4938,6 @@ out:
free(ls);
}
if (!mutex_unlocked)
pthread_mutex_unlock(&lvmetad_mutex);
return rv;
}
@ -5123,13 +5165,17 @@ static void adopt_locks(void)
* This is expected for at least one of them.
*/
rv = lm_get_lockspaces_dlm(&ls_found);
if ((rv < 0) && (rv != -ECONNREFUSED))
goto fail;
if (lm_support_dlm()) {
rv = lm_get_lockspaces_dlm(&ls_found);
if ((rv < 0) && (rv != -ECONNREFUSED))
goto fail;
}
rv = lm_get_lockspaces_sanlock(&ls_found);
if ((rv < 0) && (rv != -ECONNREFUSED))
goto fail;
if (lm_support_sanlock()) {
rv = lm_get_lockspaces_sanlock(&ls_found);
if ((rv < 0) && (rv != -ECONNREFUSED))
goto fail;
}
if (list_empty(&ls_found)) {
log_debug("No lockspaces found to adopt");
@ -5891,7 +5937,7 @@ static int main_loop(daemon_state *ds_arg)
close_client_thread();
closelog();
daemon_close(lvmetad_handle);
return 0;
return 1; /* libdaemon uses 1 for success */
}
static void usage(char *prog, FILE *file)
@ -5998,7 +6044,7 @@ int main(int argc, char *argv[])
else if (lm == LD_LM_SANLOCK && lm_support_sanlock())
gl_use_sanlock = 1;
else {
fprintf(stderr, "invalid gl-type option");
fprintf(stderr, "invalid gl-type option\n");
exit(EXIT_FAILURE);
}
break;

View File

@ -14,7 +14,6 @@
#include "tool.h"
#include "daemon-server.h"
#include "daemon-log.h"
#include "xlate.h"
#include "lvmlockd-internal.h"
@ -26,7 +25,6 @@
*/
#include "libdlm.h"
#include <pthread.h>
#include <stddef.h>
#include <poll.h>
#include <errno.h>
@ -35,7 +33,6 @@
#include <byteswap.h>
#include <syslog.h>
#include <dirent.h>
#include <sys/socket.h>
struct lm_dlm {
dlm_lshandle_t *dh;
@ -166,6 +163,9 @@ int lm_prepare_lockspace_dlm(struct lockspace *ls)
struct lm_dlm *lmd;
int rv;
if (daemon_test)
goto skip_args;
memset(sys_clustername, 0, sizeof(sys_clustername));
memset(arg_clustername, 0, sizeof(arg_clustername));
@ -473,7 +473,11 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
log_debug("S %s R %s lock_dlm", ls->name, r->name);
if (daemon_test) {
memset(vb_out, 0, sizeof(struct val_blk));
if (rdd->vb) {
vb_out->version = le16_to_cpu(rdd->vb->version);
vb_out->flags = le16_to_cpu(rdd->vb->flags);
vb_out->r_version = le32_to_cpu(rdd->vb->r_version);
}
return 0;
}
@ -689,6 +693,9 @@ int lm_hosts_dlm(struct lockspace *ls, int notify)
DIR *ls_dir;
int count = 0;
if (daemon_test)
return 0;
memset(ls_nodes_path, 0, sizeof(ls_nodes_path));
snprintf(ls_nodes_path, PATH_MAX-1, "%s/%s/nodes",
DLM_LOCKSPACES_PATH, ls->name);
@ -757,6 +764,9 @@ int lm_is_running_dlm(void)
char sys_clustername[MAX_ARGS+1];
int rv;
if (daemon_test)
return gl_use_dlm;
memset(sys_clustername, 0, sizeof(sys_clustername));
rv = read_cluster_name(sys_clustername);

View File

@ -351,6 +351,23 @@ 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);
static inline const char *mode_str(int x)
{
switch (x) {
case LD_LK_IV:
return "iv";
case LD_LK_UN:
return "un";
case LD_LK_NL:
return "nl";
case LD_LK_SH:
return "sh";
case LD_LK_EX:
return "ex";
default:
return ".";
};
}
#ifdef LOCKDDLM_SUPPORT

View File

@ -14,7 +14,6 @@
#include "tool.h"
#include "daemon-server.h"
#include "daemon-log.h"
#include "xlate.h"
#include "lvmlockd-internal.h"
@ -25,12 +24,10 @@
#include "sanlock_admin.h"
#include "sanlock_resource.h"
#include <pthread.h>
#include <stddef.h>
#include <poll.h>
#include <errno.h>
#include <syslog.h>
#include <sys/socket.h>
/*
-------------------------------------------------------------------------------
@ -205,9 +202,11 @@ int lm_data_size_sanlock(void)
*/
#define LS_BEGIN 0
#define GL_LOCK_BEGIN 65
#define VG_LOCK_BEGIN 66
#define LV_LOCK_BEGIN 67
#define GL_LOCK_BEGIN UINT64_C(65)
#define VG_LOCK_BEGIN UINT64_C(66)
#define LV_LOCK_BEGIN UINT64_C(67)
static unsigned int daemon_test_lv_count;
static int lock_lv_name_from_args(char *vg_args, char *lock_lv_name)
{
@ -341,6 +340,7 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
if (daemon_test) {
if (!gl_lsname_sanlock[0])
strncpy(gl_lsname_sanlock, ls_name, MAX_NAME);
snprintf(vg_args, MAX_ARGS, "%s:%s", lock_args_version, lock_lv_name);
return 0;
}
@ -492,6 +492,15 @@ int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name,
snprintf(lock_args_version, MAX_ARGS, "%u.%u.%u",
LV_LOCK_ARGS_MAJOR, LV_LOCK_ARGS_MINOR, LV_LOCK_ARGS_PATCH);
if (daemon_test) {
align_size = 1048576;
snprintf(lv_args, MAX_ARGS, "%s:%llu",
lock_args_version,
(unsigned long long)((align_size * LV_LOCK_BEGIN) + (align_size * daemon_test_lv_count)));
daemon_test_lv_count++;
return 0;
}
strncpy(rd.rs.lockspace_name, ls_name, SANLK_NAME_LEN);
rd.rs.num_disks = 1;
snprintf(rd.rs.disks[0].path, SANLK_PATH_LEN-1, "/dev/mapper/%s-%s", vg_name, lock_lv_name);
@ -508,12 +517,6 @@ int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name,
offset = align_size * LV_LOCK_BEGIN;
rd.rs.disks[0].offset = offset;
if (daemon_test) {
snprintf(lv_args, MAX_ARGS, "%s:%llu",
lock_args_version, (unsigned long long)1111);
return 0;
}
while (1) {
rd.rs.disks[0].offset = offset;
@ -762,6 +765,9 @@ int lm_ex_disable_gl_sanlock(struct lockspace *ls)
struct sanlk_resource **rs_args;
int rv;
if (daemon_test)
return 0;
rs_args = malloc(2 * sizeof(struct sanlk_resource *));
if (!rs_args)
return -ENOMEM;
@ -831,6 +837,9 @@ int lm_able_gl_sanlock(struct lockspace *ls, int enable)
else
gl_name = R_NAME_GL_DISABLED;
if (daemon_test)
goto out;
memset(&rd, 0, sizeof(rd));
strncpy(rd.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
@ -846,7 +855,7 @@ int lm_able_gl_sanlock(struct lockspace *ls, int enable)
ls->name, enable, rv, rd.rs.disks[0].path);
return rv;
}
out:
log_debug("S %s able_gl %s", ls->name, gl_name);
ls->sanlock_gl_enabled = enable;
@ -867,6 +876,9 @@ static int gl_is_enabled(struct lockspace *ls, struct lm_sanlock *lms)
uint64_t offset;
int rv;
if (daemon_test)
return 1;
memset(&rd, 0, sizeof(rd));
strncpy(rd.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
@ -925,8 +937,10 @@ int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset)
uint64_t offset;
int rv;
if (daemon_test)
if (daemon_test) {
*free_offset = (1048576 * LV_LOCK_BEGIN) + (1048576 * (daemon_test_lv_count + 1));
return 0;
}
memset(&rd, 0, sizeof(rd));
@ -1175,6 +1189,11 @@ int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt)
struct lm_sanlock *lms = (struct lm_sanlock *)ls->lm_data;
int rv;
if (daemon_test) {
sleep(2);
goto out;
}
rv = sanlock_add_lockspace_timeout(&lms->ss, 0, sanlock_io_timeout);
if (rv == -EEXIST && adopt) {
/* We could alternatively just skip the sanlock call for adopt. */
@ -1243,10 +1262,10 @@ int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg)
ls->name, rv, lms->ss.host_id_disk.path);
}
}
out:
if (close(lms->sock))
log_error("failed to close sanlock daemon socket connection");
out:
free(lms);
ls->lm_data = NULL;
@ -1305,6 +1324,7 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
struct lm_sanlock *lms = (struct lm_sanlock *)ls->lm_data;
struct rd_sanlock *rds = (struct rd_sanlock *)r->lm_data;
struct sanlk_resource *rs;
struct sanlk_options opt;
uint64_t lock_lv_offset;
uint32_t flags = 0;
struct val_blk vb;
@ -1378,12 +1398,16 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
rs->flags |= SANLK_RES_PERSISTENT;
log_debug("S %s R %s lock_san acquire %s:%llu",
ls->name, r->name, rs->disks[0].path,
log_debug("S %s R %s lock_san %s at %s:%llu",
ls->name, r->name, mode_str(ld_mode), rs->disks[0].path,
(unsigned long long)rs->disks[0].offset);
if (daemon_test) {
memset(vb_out, 0, sizeof(struct val_blk));
if (rds->vb) {
vb_out->version = le16_to_cpu(rds->vb->version);
vb_out->flags = le16_to_cpu(rds->vb->flags);
vb_out->r_version = le32_to_cpu(rds->vb->r_version);
}
return 0;
}
@ -1392,16 +1416,17 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
if (adopt)
flags |= SANLK_ACQUIRE_ORPHAN_ONLY;
#ifdef SANLOCK_HAS_ACQUIRE_OWNER_NOWAIT
/*
* Don't block waiting for a failed lease to expire since it causes
* sanlock_acquire to block for a long time, which would prevent this
* thread from processing other lock requests.
*/
flags |= SANLK_ACQUIRE_OWNER_NOWAIT;
#endif
rv = sanlock_acquire(lms->sock, -1, flags, 1, &rs, NULL);
memset(&opt, 0, sizeof(opt));
sprintf(opt.owner_name, "%s", "lvmlockd");
rv = sanlock_acquire(lms->sock, -1, flags, 1, &rs, &opt);
if (rv == -EAGAIN) {
/*
@ -1471,7 +1496,6 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
return -EAGAIN;
}
#ifdef SANLOCK_HAS_ACQUIRE_OWNER_NOWAIT
if (rv == SANLK_ACQUIRE_OWNED_RETRY) {
/*
* The lock is held by a failed host, and will eventually
@ -1490,7 +1514,7 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
*retry = 0;
return -EAGAIN;
}
#endif
if (rv < 0) {
log_error("S %s R %s lock_san acquire error %d",
ls->name, r->name, rv);
@ -1561,7 +1585,8 @@ int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
uint32_t flags = 0;
int rv;
log_debug("S %s R %s convert_san", ls->name, r->name);
log_debug("S %s R %s convert_san %s to %s",
ls->name, r->name, mode_str(r->mode), mode_str(ld_mode));
if (daemon_test)
goto rs_flag;
@ -1665,11 +1690,18 @@ int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
struct val_blk vb;
int rv;
log_debug("S %s R %s unlock_san r_version %u flags %x",
ls->name, r->name, r_version, lmu_flags);
log_debug("S %s R %s unlock_san %s r_version %u flags %x",
ls->name, r->name, mode_str(r->mode), r_version, lmu_flags);
if (daemon_test)
if (daemon_test) {
if (rds->vb && r_version && (r->mode == LD_LK_EX)) {
if (!rds->vb->version)
rds->vb->version = cpu_to_le16(VAL_BLK_VERSION);
if (r_version)
rds->vb->r_version = cpu_to_le32(r_version);
}
return 0;
}
if (rds->vb && r_version && (r->mode == LD_LK_EX)) {
if (!rds->vb->version) {
@ -1719,6 +1751,9 @@ int lm_hosts_sanlock(struct lockspace *ls, int notify)
int found_others = 0;
int i, rv;
if (daemon_test)
return 0;
rv = sanlock_get_hosts(ls->name, 0, &hss, &hss_count, 0);
if (rv < 0) {
log_error("S %s hosts_san get_hosts error %d", ls->name, rv);
@ -1818,6 +1853,9 @@ int lm_is_running_sanlock(void)
uint32_t daemon_proto;
int rv;
if (daemon_test)
return gl_use_sanlock;
rv = sanlock_version(0, &daemon_version, &daemon_proto);
if (rv < 0)
return 0;

View File

@ -9,7 +9,7 @@
#
# 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
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@

View File

@ -9,7 +9,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "lvmpolld-common.h"

View File

@ -9,7 +9,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _LVM_LVMPOLLD_CMD_UTILS_H

View File

@ -9,7 +9,7 @@
*
* 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
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*

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