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

Compare commits

...

1029 Commits

Author SHA1 Message Date
887f071b25 pre-release 2016-06-25 20:35:14 +01:00
15b932a70e doc: Resync kernel docs. 2016-06-25 19:59:49 +01:00
d914151591 man: lvs: move doc about --all so it's ordered alphabetically in the man page 2016-06-24 14:57:09 +02:00
a910052a2e man: document --configreport, --logonly, --reportformat 2016-06-24 14:51:20 +02:00
9a414245b9 commands: help: add missing --reportformat references 2016-06-24 14:49:13 +02:00
14da3cc793 commands: fix typo in arg assignment 2016-06-24 11:10:10 +02:00
e88e9ee9ed cleanup: clean warns from older gcc
Don't report uninitialized use by older gcc.
2016-06-24 01:10:04 +02:00
5070e7fcf7 tests: update test for modified output
We now print  vg/lv  for lv resized volume
2016-06-24 00:39:15 +02:00
fc174f6b74 tests: smaller number of devs created to fill metadata 2016-06-24 00:39:14 +02:00
1c212371fa cleanup: type cleanup
Fix return code 1.
Since we always check for !() - this fix has no other effect.
2016-06-24 00:39:14 +02:00
7c921f18e2 lvresize: let pass even protected names like _tmeta
Only later validation can decide if the volume is actually restricted
from being resized  (unlike in lvcreate time).
2016-06-24 00:39:14 +02:00
1bb7a155d1 lvresize: fixes for recent commit
Merging process and patch rework missed some bits - fix them.
2016-06-24 00:39:14 +02:00
e99a31c950 Revert "locking: trace errors from dir creation"
This reverts commit fa69ed0bc8.

This code sometimes expects to be presented with a read-only filesystem
(during some boot sequences for example) and copes appropriately with
this and it should not lead to expected error messages that might cause
unnecessary alarm.
2016-06-23 21:31:49 +01:00
a67a5d4655 tests: aux prepare_thin_metadata 2016-06-23 14:59:29 +02:00
83d483269d cleanup: drop setting lv_name
lv_name arg is only used without known LV for resolving '*lv'.
Once we know *lv, never use  lv_name ever again.

So setting it when passing *lv has not needed.
2016-06-23 14:59:29 +02:00
e5b7ebcdda cleanup: remove unused code 2016-06-23 14:59:29 +02:00
5a919e4805 cleanup: remove unused sizearg variable
It's not used for anything now.
2016-06-23 14:59:29 +02:00
4de15aa58d lvresize: return 0/1
Returning locking LV is no longer used from here, so return 1/0.
2016-06-23 14:59:29 +02:00
7092c6ba10 lvresize: support more resized LVs
Add code to support more LVs to be resized through a same code path
using a single lvresize_params struct.
(Now it's used for thin-pool metadata resize,
next user will be snapshot virtual resize).

Update code to adjust percent amount resize for use_policies.

Properly activate inactive thin-pool in case of any pool resize
as the command should not 'deffer' this operation to next activation.
2016-06-23 14:59:27 +02:00
d44e653fe1 lvresize: do not pass struct cmd
Use common API design and pass just LV pointer to lv_manip.c functions.
Read cmd struct via    lv->vg->cmd when needed.
Also do not try to return EINVALID_CMD_LINE error when we
have already openned VG - this error code can only be returned before
locking VG.
2016-06-23 14:57:09 +02:00
5013999c8b lvresize: pass only needed params to _fsadm_cmd
Do not pass whole lvresize_params into _fsadm_cmd,
and give it only needed args.
2016-06-23 14:57:09 +02:00
d30c2cec88 lvresize: check pvh list is vg->pvs
Instead of checking lp->argc for arg count, compare directly whether
passed pvh is vg->pvs.
2016-06-23 14:57:09 +02:00
f45b689406 lvresize: update lvresize_params struct
Reorganise  struct lvresize_params to better fit lvresize needs to be
able to resize more then just a single LV.
2016-06-23 14:57:09 +02:00
698082e678 cleanup: use display_lvname 2016-06-23 14:57:08 +02:00
6268d0a080 cleanup: add dots to some messages
Add missing dots and one comment.
2016-06-23 14:57:08 +02:00
0a525832f9 cleanup: code lines reodered 2016-06-23 14:57:08 +02:00
3a4107c982 lvresize: drop extra sigint handling
yes_no_prompt() now already handles signal checking,
so drop redundant test.
2016-06-23 14:57:08 +02:00
d578d8d3a1 lvresize: inform about ignored args with --use-polices
When --use-polices is specified, all size args are meaningless,
as the resize is based upon policy. So just keep user informed.
2016-06-23 14:57:08 +02:00
58d414f7f5 lvresize: move and extend resizefs ignoring check
Move check for 'ignoring' --resizefs option and extend check
for some more types.
2016-06-23 14:57:08 +02:00
fa69ed0bc8 locking: trace errors from dir creation 2016-06-23 14:57:06 +02:00
dc8c5c1886 monitoring: preserve monitoring status during update
Ignore monitoring during whole update (suspend/resume) of thin-pool.
2016-06-23 14:56:10 +02:00
eb51be4fbe activation: _lv_active returns 0 on error
We have only 2 users of _lv_active() - one was already checking for ==1
while the other use (_lv_is_active()) could have take '-1' as a sign of having
an LV active. So return 0 and log_debug also the reason while detection
has failed (i.e. in case  --driverload n  - it's kind of expectable,
but might have confused user seeing just <backtrace>).
2016-06-23 14:55:35 +02:00
af36f5ad36 activation: switch to warning
Since this function does not have a way to return error use correct
reporting level as warning.
2016-06-23 14:53:59 +02:00
751163a743 libdm: log: remove log_print_bypass_report calls and register new print_log_libdm for libdm during lvm initialization instead
This fixes commit f50d4011cd which
introduced a problem when using older lvm2 code with newer libdm.
In this case, the old LVM didn't recognize new _LOG_BYPASS_REPORT flag
that libdm-report code used. This ended up with no output at all
from libdm where log_print_bypass_report was called because the
_LOG_BYPASS_REPORT was not masked properly in lvm2's print_log fn
which was called as callback function for logging.

With this patch, the lvm2 registers separate print_log_libdm logging
function for libdm instead. The print_log_libdm is exactly the same
as print_log (used throughout lvm2 code) but it checks whether we're
printing common line on output where "common" means not going to stderr,
not a warning and not an error and if we are, it adds the
_LOG_BYPASS_REPORT flag so the log_print goes directly to output, not
to any log report.

So this achieves the same goal as in f50d4011cd,
just doing it in a way that newer libdm is still compatible with older
lvm2 code (libdm-report is the only code using log_print).

Looking at the opposite mixture - older libdm with newer lvm2 code,
that won't be compilable because the new log report functionality
that is in lvm2 also requires new dm_report_group_* libdm functions
so we don't need to care here.
2016-06-23 14:45:52 +02:00
6eeb66e51d log: move original print_log code to _vprint_log and make print_log a wrapper over _vprint_log
Move code from original print_log fn to a separate _vprint_log function
that accepts va_list and make print_log a wrapper over _vprint_log.
The print_log just initializes the va_list and uses it for _vprint_log
call now. This way, we can reuse _vprint_log if needed.
2016-06-23 14:45:52 +02:00
79eaaee50a filters: add comments about internal filter position in filter chain 2016-06-23 09:37:51 +02:00
6513a7a449 lvconvert: Fix --stripes handling.
Only treat --stripes as meaning --type striped if no other type was
first detected.  If a segtype got selected, don't override it later.
2016-06-22 22:10:42 +01:00
ebd2758dab vgimportclone: add native command
This is cleaner and more efficient than the script.
The args and usage are unchanged.
2016-06-22 13:13:10 -05:00
dfc516f9bf lvconvert: Refactor argument handling code.
Begin disentangling the different lvconvert modes of operation
from each other.
2016-06-22 18:40:22 +01:00
7e671e5dd0 tools: Use arg_is_set instead of arg_count. 2016-06-21 22:24:52 +01:00
6c269e639a vgcfgrestore: rescan to reenable lvmetad on error path
In commit 6ae22125, vgcfgrestore began disabling lvmetad
while running, and rescanned to enable it again at the end,
but missed the rescanning/enabling in the error case.
2016-06-21 11:40:42 -05:00
f96de67490 vgcfgrestore: check for missing device
The missing device will generally be seen earlier
and cause the command to not reach this point, but
check anyway for completeness.
2016-06-20 16:02:07 -05:00
47a29f6b2e lvmlockd: always try to connect to lvmetad
Reconnect to lvmetad if either the send fails (e.g. lvmetad
was restarted since lvmlockd last connected), or if no
lvmetad connection exists (e.g. lvmetad was started after
lvmlockd so no previous connection existed.)
2016-06-20 14:01:46 -05:00
b12961e7eb lvmetad: process new connections after shutdown signal
Currently, a shutdown signal will cause lvmetad to quit
responding to new connections, but not actually exit until
all connections are gone.  If a program is maintaining a
long running connection (e.g. lvmlockd, or even an lvm
command) when lvmetad gets a shutdown signal, then all
further commands will hang indefinately waiting for a
response that won't be sent.

With this patch, make lvmetad continue handling new
connections even after a shutdown signal.  It will exit
once all connections are gone.
2016-06-20 13:19:02 -05:00
6ae22125c6 vgcfgrestore: use lvmetad disabled state
Previously, vgcfgrestore would attempt to vg_remove the
existing VG from lvmetad and then vg_update to add the
restored VG.  But, if there was a failure in the command
or with vg_update, the lvmetad cache would be left incorrect.
Now, disable lvmetad before the restore begins, and then
rescan to populate lvmetad from disk after restore has
written the new VG to disk.
2016-06-20 11:19:49 -05:00
cae6591b9d vgscan: fix process_each args
zero/null args were mixed up.
2016-06-20 11:18:36 -05:00
d1d3820219 conf: add more comments for new settings related to output format and log report 2016-06-20 16:21:38 +02:00
99ea03571a cleanup: log: use hex numbers instead of decimal for _LOG_* 2016-06-20 14:22:31 +02:00
a77732c180 log: add 'label' log report object type; annotate process_each_label with log_set_report_object_{type, id_and_name} and report_log_ret_code 2016-06-20 14:05:13 +02:00
db6b4c1eef report: compare --configreport value with basic report type
Reporting commands can be of different types (even if the command name
is the same):
  - pvs command can be either of PVS, PVSEGS or LABEL report type,
  - vgs command is of VGS report type,
  - lvs command is of LVS or SEGS report type.

Use basic report type when looking for report prefix used for
--configreport option.

This means that:
  - 'pvs --configreport pv' applies to PVS, PVSEGS or LABEL report type
  - 'vgs --configreport vg' applies to VGS report type
  - 'lvs --configreport lv' applies to LVS and SEGS report type
2016-06-20 14:04:37 +02:00
2593cab5c4 commands: add --configreport arg for all relevant commands 2016-06-20 11:57:24 +02:00
083e538030 conf: regenerate profile templates 2016-06-20 11:33:43 +02:00
92caebab95 report: add --logonly arg to report only log for a command 2016-06-20 11:33:43 +02:00
3e8e8ddb46 report: use report type description for report's name if using DM_REPORT_GROUP_BASIC output format 2016-06-20 11:33:43 +02:00
5b93db6566 libdm: select: recognize special selection string 'all' as an alias for blank selection string 2016-06-20 11:33:43 +02:00
1127b090bd conf: add log/command_log_selection config setting 2016-06-20 11:33:43 +02:00
cee1aedf12 log: use separate 'orphan' report object type for orphan VGs 2016-06-20 11:33:43 +02:00
89e2aef63a tools: add 'lvm lastlog' command for interactive query and display of last command's log
If we're running in lvm shell, we can keep last command's log report
for further query with possible different selection criteria for easy
log lookup.
2016-06-20 11:33:43 +02:00
c33c0545af refactor: move 'interactive' field from struct command_line to struct cmd_context as 'is_interactive' switch 2016-06-20 11:33:43 +02:00
0ab1187740 log: annotate processing code with report_current_object_cmdlog 2016-06-20 11:33:43 +02:00
6ca28ca4c6 log: annotate processing code with log_set_report_{context,object_type,id_and_name} 2016-06-20 11:33:43 +02:00
1b107adc1d report: add 'multiple_output' arg to report_init
Some reports may be reported several times with possible different
selection criteria, just like command log report.
2016-06-20 11:33:43 +02:00
2078b842fb libdm: report: add dm_report_set_selection
Since we can do repeated dm_report_output calls now, we also like
to be able to set selection for each of these outputs.
2016-06-20 11:33:43 +02:00
f2facdc1d0 libdm: report: add DM_REPORT_OUTPUT_MULTIPLE_TIMES report flag to keep report data even after output is done
The DM_REPORT_OUTPUT_MULTIPLE_TIMES instructs reporting code to
keep rows even after dm_report_output call - the rows are not
destroyed in this case which makes it possible to call dm_report_output
multiple times.
2016-06-20 11:33:43 +02:00
0ba5f4b8e9 refactor: move field width calculation and sort preparation from _do_report_object to dm_report_output
This also prepares code for repeated dm_report_output calls.
2016-06-20 11:33:42 +02:00
102cc4c1e2 libdm: report: remember special field to display selection status in struct row's field_sel_status variable
This allows for moving parts of the code from dm_report_object to
dm_report_output which is important for subsequent patches that allow
for repeated dm_report_output, not destroying rows on each
dm_report_output call.
2016-06-20 11:33:42 +02:00
f50d4011cd log: also pass log_print through report and add log_print_bypass_report for use in libdm-report for direct print without report
log_print is used during cmd line processing to log the result of the
operation (e.g. "Volume group vg successfully changed" and similar).

We don't want output from log_print to be interleaved with current
reports from group where log is reported as well. Also, the information
printed by log_print belongs to the log report too, so it should be
rerouted to log report if it's set.

Since the code in libdm-report which is responsible for doing the report
output uses log_print too, we need to use a different kind of log_print
which bypasses any log report currently used for logging (...simply,
we can't call log_print to output the log report itself which in turn
would again reroute to report - the report would never get on output
this way).
2016-06-20 11:33:42 +02:00
fe63715f25 report: add report_current_object_cmdlog fn as a shortcut for reporting current object's log item 2016-06-20 11:33:42 +02:00
7d4a15e53a log: log warnings and errors via report if set; add log_set_report* fns
This patch adds structures and functions to reroute error and warning
logs to log report, if it's set.

There are 5 new functions:
  - log_set_report
    Set log report where logging will be rerouted.

  - log_set_report_context
    Set context globally so any report_cmdlog call will use it.

  - log_set_report_object_type
    Set object type globally so any report_cmdlog call will use it.

  - log_set_report_object_name_and_id
    Set object ID and name globally so any report_cmdlog call will use it.

  - log_set_report_object_group_and_group_id
    Set object group ID and name globally so any report_cmdlog call will use it.

These functions will be called during LVM command processing so any logs
which are rerouted to log report contain proper information about current
processing state.
2016-06-20 11:33:42 +02:00
8cfc385491 toollib: make it possible to also process internal VGs, add 'include_internal' switch to process_each_vg fn
The lvm fullreport works per VG and as such, the vg, lv, pv, seg and
pvseg subreport is done for each VG. However, if the PV is not part of
any VG yet, we still want to display pv and pvseg subreports for these
"orphan" PVs - so enable this for lvm fullreport's process_each_vg call.
2016-06-20 11:33:42 +02:00
31aaa3be71 report: check report type and options used for full report's subreports
If we have fullreport, make sure that the options/sort keys used for
each report doesn't change its type - we want to preserve the original
type so it's always 5 different subreports within fullreport (vg, lv, pv,
seg, pvseg). Since we have all report types within fullreport, users
should add fields under proper subreport type - this minimizes
duplication of info displayed on output.
2016-06-20 11:33:42 +02:00
b864a06221 report: recognize selection (-S|--select) for each subreport; make -S|--select groupable 2016-06-20 11:33:42 +02:00
e081203f3e report: recognize list of keys to sort report by (-O|--sort) for each subreport; make -O|--sort groupable 2016-06-20 11:33:42 +02:00
bd26684d5d report: recognize list of fields to report (-o|--options) for each subreport 2016-06-20 11:33:42 +02:00
80ffaefb88 report: add _get_report_idx_from_name and _should_process_report_idx helper fns
Prepare for recognition of cmd line options for each subreport within
one command.
2016-06-20 11:33:42 +02:00
28b4c48e2a args: add --configreport arg 2016-06-20 11:33:42 +02:00
d23c5b9318 args: add priorities for grouping args
Groupable args (the ones marked with ARG_GROUPABLE flag) start a new
group of args if:
  - this is the first time we hit such a groupable arg,
  - or if non-countable arg is repeated.

However, there may be cases where we want to give priorities when
forming groups and hence force new group creation if we hit an arg
with higher grouping priority.

For example, let's assume (for now) hypothetical sequence of args used:

  lvs -o lv_name --configreport log -o log_type --configreport lv -o +vg_name

Without giving any priorites, we end up with:

  lvs -o lv_name --configreport log -o log_type --configreport lv -o +vg_name
     |                            | |                           | |          |
     \__________GROUP1___________/   \________GROUP2___________/   \_GROUP3_/

This is because we hit "-o" as the first groupable arg. The --configreport,
even though it's groupable too, it falls into the previous "-o" group.

While we may need to give priority to the --configreport arg that should
always start a new group in this scenario instead:

  lvs -o lv_name --configreport log -o log_type --configreport lv -o +vg_name
      |         | |                            | |                           |
      \_GROUP1_/   \_________GROUP2___________/   \_________GROUP3__________/

So here "-o" started a new group but since "--configreport" has higher
priority than "-o", it starts fresh new group now and hence the rest of
the command line's args are grouped by --configreport now.
2016-06-20 11:33:42 +02:00
9c37b7ed7c conf: add report/{vgs,pvs,lvs,pvsegs,segs}_{cols,sort}_full config settings 2016-06-20 11:33:42 +02:00
26c43c6ce5 commands: report: add lvm fullreport command
lvm fullreport executes 5 subreports (vg, pv, lv, pvseg, seg) per each VG
(and so taking one VG lock each time) within one command which makes it
easier to produce full report about LVM entities.

Since all 5 subreports for a VG are done under a VG lock, the output is
more consistent mainly in cases where LVM entities may be changed in
parallel.
2016-06-20 11:33:42 +02:00
f1e7f35bb5 commands: recognize --reportformat option for other commands
Enables --reportformat option for all command using processing_handle
(and process_each_* fn variant), that is: lvchange, lvcreate, lvdisplay,
lvextend, lvreduce, lvremove, lvrename, lvresize, lvscan, pvchange,
pvresize, pvcreate, pvdisplay, pvmove, pvremove, pvscan, vgcfgbackup,
vgchange, vgck, vgconvert, vgcreate, vgdisplay, vgexport, vgextend,
vgimport, vgmknodes, vgreduce, vgremove, vgrename command.
2016-06-20 11:33:42 +02:00
f8a93763e5 commands: recognize --reportformat option for pvs,vgs,lvs and devtypes command
Enables --reportformat options for pvs, vgs, lvs, devtypes command.
2016-06-20 11:33:41 +02:00
10a1b9e182 report: add current report to existing group
Add any report (pvs/vgs/lvs) currently processed to current report group
which is part of processing handle and which already contains log
report. This way both log report and pvs/vgs/lvs report will be
reported as a whole within a group, thus having same output format as
selected by --reportformat option.
2016-06-20 11:33:41 +02:00
f752a95302 toollib: add 'parent' field to processing_handle; init report format only if there's no parent
If there's parent processing handle, we don't need to create completely
new report group and status report - we'll just reuse the one already
initialized for the parent.

Currently, the situation where this matter is when doing internal report
to do the selection for processing commands where we have parent processing
handle for the command itself and processing handle for the selection
part (that is selection for non-reporting tools).
2016-06-20 11:33:41 +02:00
c099f531fb toollib: add report_group and log_rh to processing_handle and initialize cmd processing log report
Wire up report group creation with log report in struct
processing_handle and call report_format_init during processing handle
initialization (init_processing_handle fn) and destroy it while
destroing processing handle (destroy_processing_handle fn).

This way, all the LVM command processing using processing handle
has access to log report via which the current command log
can be reported as items are processed.
2016-06-20 11:33:41 +02:00
213434d426 report: separate common report and per-report args
Separating common report and per-report arguments prepares the code for
handling several reports per one command (for example, the command log
report and LVM command report itself).

Each report can have sort keys, options (fields), list of fields to
compact and selection criteria set individually. Hooks for setting these
per report within one command will be a part of subsequent patches, this
patch only separates new struct single_report_args out of existing
struct report_args.
2016-06-20 11:33:41 +02:00
bd0a0ae36b conf: add log/report_command_log config setting 2016-06-20 11:33:41 +02:00
a08e02afbf conf: add report/output_format config setting
New report/output_format configuration sets the output format used
for all LVM commands globally. Currently, there are 2 formats
recognized:
   - basic (the classical basic output with columns and rows, used by default)
   - json (output is in json format)
2016-06-20 11:33:41 +02:00
79a74e9aae toollib: add report_format_init fn to create report group and to create/add log report handle
Add new --reportformat option and new report_format_init function that
checks this option and creates new report group accordingly, also
preparing log report handle and adding it to the report group just
created.
2016-06-20 11:33:41 +02:00
c36d4632a6 conf: add log/command_log_{sort,cols} config settings 2016-06-20 11:33:40 +02:00
99c2a2b960 report: add CMDLOG report type
This is a preparation for new CMDLOG report type which is going to be
used for reporting LVM command log.

The new report type introduces several new fields (log_seq_num, log_type,
log_context, log_object_type, log_object_group, log_object_id, object_name,
log_message, log_errno, log_ret_code) as well as new configuration settings
to set this report type (report/command_log_sort and report/command_log_cols
lvm.conf settings).

This patch also introduces internal report_cmdlog helper function
which is a wrapper over dm_report_object to report command log via
CMDLOG report type and which is going to be used throughout the code
to report the log items.
2016-06-20 11:33:08 +02:00
094fce3776 libdm: report: implement DM_REPORT_GROUP_JSON for JSON report output
This patch introduces DM_REPORT_GROUP_JSON report group type. When using
this group type and when pushing a report to such a group, these flags
are automatically unset:

   DM_REPORT_OUTPUT_ALIGNED
   DM_REPORT_OUTPUT_HEADINGS
   DM_REPORT_OUTPUT_COLUMNS_AS_ROWS

...and this flag is set:

   DM_REPORT_OUTPUT_BUFFERED

The whole group is encapsulated in { } for the outermost JSON object
and then each report is reported on output as array of objects where
each object is the row from report:

  {
     "report_name1": [
         {field1="value", field2="value",...},
         {field1="value", field2="value",...}
         ...
     ],
     "report_name2": [
         {field1="value", field2="value",...},
         {field1="value", field2="value",...}
         ...
     ]
     ...
  }
2016-06-20 10:42:26 +02:00
230b7ff0f6 libdm: report: implement DM_REPORT_GROUP_BASIC for extended report output
This patch introduces DM_REPORT_GROUP_BASIC report group type. This
type has exactly the classical output format as we know from before
introduction of report groups. However, in addition to that, it allows
to put several reports into a group - this is the very basic grouping
scheme that doesn't change the output format itself:

  Report: report1_name
  Header1  Header2 ...
  value    value   ...
  value    value   ...
  ...      ...     ...

  Report: report2_name
  Header1  Header2 ...
  value    value   ...
  value    value   ...
  ...      ...     ...
2016-06-20 10:42:26 +02:00
a9fe57db1c libdm: report: implement DM_REPORT_GROUP_SINGLE for a group containing single report only
There's no change in output for this report group type - with this type,
we only make sure there's always only one report in a group at a time,
not more.
2016-06-20 10:42:18 +02:00
9c8f912ea7 libdm: report: introduce dm_report_group
This patch introduces DM report group (represented by dm_report_group
structure) that is used to group several reports to make a whole. As a
whole, all the reports in the group follow the same settings and/or
formatting used on output and it controls that the output is properly
ordered (e.g. the output from different reports is not interleaved
which would break readability and/or syntax of target output format
used for the whole group).

To support this feature, there are 4 new functions:
  - dm_report_group_create
  - dm_report_group_push
  - dm_report_group_pop
  - dm_report_group_destroy

From the naming used (dm_report_group_push/pop), it's clear the reports
are pushed onto a stack. The rule then is that only the report on top
of the stack can be reported (that means calling dm_report_output).
This way we make sure that the output is not interleaved and provides
determinism and control over the output.

Different formats may allow or disallow some of the existing report
flags controlling output itself (DM_REPORT_OUTPUT_*) to be set or not so
once the report is pushed to a group, the grouping code makes sure that
all the reports have compatible flags set and then these flags are
restored once each report is popped from the report group stack.

We also allow to push/pop non-report item in which case such an item
creates a structure (e.g. to put several reports together with any
opening and/or closing lines needed on output which pose as extra
formatting structure besides formatting the reports).

The dm_report_group_push function accepts an argument to pass any
format-specific data needed (e.g. handle, name, structures passed
along while working with reports...).

We can call dm_report_output directly anytime we need (with the only
restriction that we can call dm_report_output only for the report that
is currently on top of the group's stack). Or we don't need to call
dm_report_output explicitly in which case all the reports in a stack are
reported on output automatically once we call dm_report_group_destroy.
2016-06-20 09:26:51 +02:00
029f51e1a8 vgreduce: fix location of lvmlockd global lock
The lvmlockd global lock was missing the non-repair case,
which caused the new orphan PV created by vgreduce to
not be seen by other hosts.
2016-06-17 12:22:58 -05:00
899a4ca275 lvmlockd: fix dropping PVs in rescanning VG
This fixes a problem in commit ae0a8740c.  The problem
in that commit was that all existing PVs are initially
dropped from lvmetad.  This works if the VG is updated
at the end, which replaces the dropped PVs, but if the
rescan finds that the VG seqno is unchanged, it leaves
the cached VG in place.  So, we should only drop the
existing PVs in lvmetad when the VG is going to be updated.
2016-06-17 12:21:09 -05:00
ab7ade4095 post-release 2016-06-17 14:10:20 +01:00
38cc03605c pre-release 2016-06-17 14:10:20 +01:00
a23655ab3b tools: add missing destroy_processing_handle in pvscan and vgreduce code 2016-06-17 13:29:33 +02:00
f77fe436af pvscan: don't activate LVs when use_lvmetad=0
commit 15da467b was meant to address the case where
use_lvmetad=1 in lvm.conf, and lvmetad is not available,
in which case, pvscan --cache -aay should activate LVs.

But the commit unintentionally also changed the case
where use_lvmetad=0 in lvm.conf, in which case
pvscan --cache -aay should not activate LVs, so fix
that here.
2016-06-16 12:04:05 -05:00
944ae4d2df pvscan: fix lvmlockd global lock
This should have been removed when pvscan was
recently converted to use process_each_pv which
does the lvmlockd locking.
2016-06-15 16:51:36 -05:00
15da467b52 pvscan: do activation when lvmetad is not running
When pvscan --cache -aay fails to connect to lvmetad it will
simply exit and do nothing.  Change this so that it will
skip the lvmetad cache step and do the activation step from
disk.
2016-06-15 14:19:18 -05:00
ae0a8740c5 lvmlockd: fix rescanning VG
Previously, new PVs that were added to the VG were not scanned.
2016-06-15 11:36:30 -05:00
49a8d1a85e post-release 2016-06-11 00:14:00 +01:00
f2d1f5e927 pre-release 2016-06-11 00:08:08 +01:00
2d384954ad lvmdbusd: Remove duplicate test code 2016-06-10 16:05:03 -05:00
a1febff857 lvmdbusd: Add test for DataLv & MetaDataLv
Added tests which expose an issue found with these properties.
2016-06-10 16:05:03 -05:00
cdf06044e1 lvmdbusd: Create correct LV object type
We were initially looking to see if an LV was hidden and if it was we were
creating an instance of a LvCommon object to represent it.  Thus if we
had a hidden cache pool for example we were missing the methods and
properties for the cache pool.  However, when we create the object path,
any hidden LVs, regardless of type/functionality will be placed in the
hidden path.
2016-06-10 16:05:03 -05:00
b81186e535 lvmdbusd: Add method get_object_path_by_lvm_id
The object manager method get_object_by_lvm_id was used in many cases for
the sole reason of getting the object path for the object.  Instead of
retrieving the object and then calling 'dbus_object_path' on the object, we
are adding a method which returns the object path.
2016-06-10 16:04:43 -05:00
b717e8fe1d lvmdbusd: Rename get_object_path_by_lvm_id
Renaming to get_object_path_by_uuid_lvm_id, to clarify that both the uuid
and the lvm id are required.
2016-06-10 15:28:42 -05:00
41ebed7077 lvmdbusd: Change print statement to py3 syntax 2016-06-10 15:28:42 -05:00
b717c5efae lvmdbusd: Bug fix for missing LV properties
When we are processing the LVs we need to build up dbus objects from least
dependent to most dependent, so that we have information available when
constructing.
2016-06-10 15:28:42 -05:00
e04705b305 lvmdbusd: Add data_lv and metadata_lv to cache pool interface
See: https://bugzilla.redhat.com/show_bug.cgi?id=1342558
2016-06-10 15:28:42 -05:00
3bf43a65fe lvmdbusd: Add roles property to LV common interface
See: https://bugzilla.redhat.com/show_bug.cgi?id=1342559
2016-06-10 15:28:42 -05:00
8a667f5887 WHATS_NEW: add recent changes 2016-06-10 13:39:23 -05:00
ad414e5ad6 cleanup: typo in WHATS_NEW_DM 2016-06-10 16:01:22 +02:00
35612bd27c display: yes no prompt improvement
Original code missed to catch all apperances of SIGINT.
Also enhance logging when running in shell without tty.
Accept this regex as valid input:
'^[ ^t]*([Yy]([Ee]([Ss]|)|)|[Nn]([Oo]|))[ ^t]*$'
2016-06-10 16:00:31 +02:00
cfdc87b623 lvmdump: also collect output from lsblk command when running lvmdump -s
lsblk provides nice and quick overview of the storage/sysfs structure
that is useful for debugging - collect its output when running lvmdump -s.
2016-06-09 13:54:15 +02:00
86f9271457 vgcreate, pvcreate, vgextend: don't use a device with duplicates
If duplicate orphan PVs exist, don't allow one of them to be
used for vgcreate/pvcreate/vgextend.
2016-06-07 15:21:07 -05:00
199b7b55c2 lvmcache: fix duplicate handling with multiple scans
Some commands scan labels to populate lvmcache multiple
times, i.e. lvmcache_init, scan labels to fill lvmcache,
lvmcache_destroy, then later repeat

Each time labels are scanned, duplicates are detected,
and preferred devices are chosen.  Each time this is done
within a single command, we want to choose the same
preferred devices.  So, check for existing preferences
when choosing preferred devices.

This also fixes a problem with the list of unused duplicate
devs when run in an lvm shell.  The devs had been allocated
from cmd memory, resulting in invalid list entries between
commands.
2016-06-07 15:15:51 -05:00
01156de6f7 lvmcache: add optional dev arg to lvmcache_info_from_pvid
A number of places are working on a specific dev when they
call lvmcache_info_from_pvid() to look up an info struct
based on a pvid.  In those cases, pass the dev being used
to lvmcache_info_from_pvid().  When a dev is specified,
lvmcache_info_from_pvid() will verify that the cached
info it's using matches the dev being processed before
returning the info.  Calling code will not mistakenly
get info for the wrong dev when duplicate devs exist.

This confusion was happening when scanning labels when
duplicate devs existed.  label_read for the first dev
would add an info struct to lvmcache for that dev/pvid.
label_read for the second dev would see the pvid in
lvmcache from first dev, and mistakenly conclude that
the label_read from the second dev can be skipped
because it's already been done.  By verifying that the
dev for the cached pvid matches the dev being read,
this mismatch is avoided and the label is actually read
from the second duplicate.
2016-06-07 15:15:47 -05:00
ed6ffc7a34 lvmetad: handle update failures
If a command gets stuck during an lvmetad update, lvmetad
will cancel that update after the timeout.  The next command
to check the lvmetad will see that lvmetad needs to be
populated because lvmetad will return token of "none" after
a timed out update (same as when lvmetad is not populated
at all after starting.)

If a command gets an error during an lvmetad update, it
will now just quit and leave its updating token in place.
That update will be cancelled after the timeout.
2016-06-07 10:17:00 -05:00
851ccfccaf lvmetad: remove disabled case for "scan error"
Failures while populating lvmetad will be handling
differently in a subsequent commit.
2016-06-07 10:17:00 -05:00
0e7f352c70 lvmetad: define special update in progress string 2016-06-07 10:17:00 -05:00
7ae05adf46 blkdeactivate: fix regression in blkdeactivate causing dm and md devices to be skipped.
Commit #5b3a4a9 caused the "name" variable to be cleared if
declaration and assignment is on two lines so put it back
so it's on one line for it to work again.
2016-06-06 14:57:46 +02:00
7c894911ae post-release 2016-06-03 23:20:43 +01:00
767c9d653e pre-release 2016-06-03 23:16:50 +01:00
b321d2b1b9 pvmove: disallow tag args
pvmove began processing tags unintentionally from commit,
6d7dc87cb pvmove: use toollib

pvmove works on a single PV, but tags can match multiple PVs.
If we allowed tags, but processed only the first matching PV,
then the resulting PV would be unpredictable.

Also, the current processing code does not allow us to simply
report an error and do nothing if more than one PV matches the tag,
because the command starts processing PVs as they are found,
so it's too late to do nothing if a second PV matches.
2016-06-03 09:56:48 -05:00
68e0979724 man: fixed typo in lvcreate.8
It's supposed to be "smaller than" instead of "smaller then".
2016-06-03 12:46:47 +02:00
8e4db009b8 cleanup: compile fixes for --disable-devmapper
Make lvm2 compilable when configured with: --disable-devmapper.
2016-06-03 12:46:43 +02:00
8012c223e0 man: lvmconfig: add note about --type diff and --mergedconfig 2016-06-02 14:07:07 +02:00
687bc5cecf lvmconfig: fix lvmconfig --type diff to display complete diff if config cascade used
If configuration consists of several sources in config cascade
("config cascade" defined in man lvmconfig(8)), lvmconfig displayed
only difference from defaults of the topmost config in the cascade.
Fix lvmconfig to display complete difference, considering all
the configuration in the cascade.

For example, before this patch:

	(use_lvmetad=0 set in lvm.conf which differs from defaults)
	$ lvmconfig --type diff
	global {
		use_lvmetad=0
	}

	(compact_output=1 set on cmd line)
	$ lvmconfig --type diff --config report/compact_output=1
	report {
		compact_output=1
	}

	(headings=0 set in profile)
	$ lvmconfig --type diff --commandprofile test
	report {
		headings=0
	}

	(difference in topmost configuration source is displayed)
	$ lvmconfig --type diff --commandprofile test --config report/compact_output=1
	report {
		compact_output=1
	}

With this patch applied (the config cascade is merged before looking for
difference from defaults in configuration):

	$ lvmconfig --type diff
	global {
		use_lvmetad=0
	}

	$ lvmconfig --type diff --config report/compact_output=1
	report {
		compact_output=1
	}
	global {
		use_lvmetad=0
	}

	$ lvmconfig --type diff --profile test
	report {
		headings=0
	}
	global {
		use_lvmetad=0
	}

	$ lvmconfig --type diff --profile test --config report/compact_output=1
	report {
		headings=0
		compact_output=1
	}
	global {
		use_lvmetad=0
	}
2016-06-02 13:49:38 +02:00
fc37ee63c0 make: add generated parts of lvmdbusd to DISTCLEAN_TARGETS for make distclean 2016-06-02 11:58:54 +02:00
21cefd3f07 cleanup: use display_name 2016-06-01 17:40:26 +02:00
a5d65b4a51 tests: check losetup -P is correctly handled
Validate pvcreate will not overwrite partitioned loop device.
2016-06-01 17:37:52 +02:00
d73a83e8cf tests: extend prepare_loop
Treat args after size  as 'extra' params for losetup.
2016-06-01 17:37:52 +02:00
d37a26b680 devices: handle partscan loop devices
Treat loop device created with 'losetup -P' as regular
partitioned device - so if it has partition table,
prevent its usage in commands like 'pvcreate'.

Before 'pvcreate /dev/loop0' could have erased and formated as PV,
after this patch, device is filtered out and cannot be used.
2016-06-01 17:37:47 +02:00
3d333e5a29 coverity: fix warnings about missing return value check for sscanf
All the variables for sscanf in lvmlockctl.c and lvmlockd-sanlock.c are
zeroed before sscanf call so the failure is detected by seeing the zero
value instead of proper one in subsequent code - so use (void) for
sscanf calls to ignore return value here.
2016-05-31 10:06:25 +02:00
48877e215d coverity: missing check for id_write_format return value 2016-05-31 09:56:10 +02:00
5b3a4a9595 coverity: blkdeactivate: separate format and args for printf and declare and assign separately to avoid masking return values 2016-05-31 09:39:06 +02:00
02d67848eb coverity: fix possible resource leak of descendants_buffer in _print_historical_lv fn 2016-05-31 09:36:58 +02:00
cfe7d2368c tests: add dmstats to CLEAN_TARGETS for make clean 2016-05-31 09:14:23 +02:00
4fb224a553 toollib: properly reset selection handle on selection failure in select_match_{pv,vg,lv} 2016-05-31 09:08:59 +02:00
e4ec6bcdd3 report: fix lvm devtypes internal error if -S is used with field name from pvs/vgs/lvs
Before this fix, when reporting 'lvm devtypes', the report was
initialized with incorrect reserved values - the ones used for
pvs/vgs/lvs report were used instead of NULL value (because devtypes
doesn't have any reserved values).

For example, trying to (incorrectly) use lv_name for the -S|--select
with lvm devtypes which doesn't have this field at all:

Before this patch (internal error issued):

$ lvm devtypes -S 'lv_name=lvol0'
  Internal error: _check_reserved_values_supported: field-specific reserved value of type 0x0 for field  not supported
  Internal error: dm_report_init_with_selection: trying to register unsupported reserved value type, skipping report selection
  DevType       MaxParts Description
  aoe                 16 ATA over Ethernet
  ataraid             16 ATA Raid
  bcache               1 bcache block device cache
  ...

With this patch applied (correct error displayed about
unrecognized selection field):

$ lvm devtypes -S 'lv_name=lvol0'
  Device Types Fields
  -------------------
    devtype_name           - Name of Device Type exactly as it appears in /proc/devices. [string]
    devtype_max_partitions - Maximum number of partitions. (How many device minor numbers get reserved for each device.) [number]
    devtype_description    - Description of Device Type. [string]

  Special Fields
  --------------
    selected               - Set if item passes selection criteria. [number]
    help                   - Show help. [unselectable number]
    ?                      - Show help. [unselectable number]

  Unrecognised selection field: lv_name
  Selection syntax error at 'lv_name=lvol0'.
  Use 'help' for selection to get more help.
2016-05-30 16:46:18 +02:00
815f1ee26d toollib: simplify internal selection calls for non-reporting tools
Some of the variables were set superfluously - we can just use existing
"struct processing_handle" which includes "struct selection_handle".
2016-05-30 16:44:18 +02:00
7d4d0ff606 tests: check thin is not flushed for status
We finally approach a moment where we generally avoid
flushing thin-pool with every lvs command...
2016-05-27 17:25:52 +02:00
88eeb004e9 snapshot: for invalid snapshot show 100%
Recent commit 92eba53a79 started to report
empty "" data usage of invalid snapshot, restore 100% to be shown.
2016-05-27 17:25:37 +02:00
43dfc2011c tests: stacked snapshot merge 2016-05-27 15:47:24 +02:00
a67adbfe2e tests: check cache_mode change on cachepool 2016-05-27 15:47:24 +02:00
090ecaabed debug: use display_lvname 2016-05-27 15:47:24 +02:00
04003cf1ff cache: add log_error on error path
Validate and report error when lv_cache_status is called
for inactive LV, or pending delete or unused cache_pool.
2016-05-27 15:47:24 +02:00
ecfb90de74 report: convert more options to use single status
Convert fields into using a single status ioctl call per LV.
This is a bit tricky since when there are more complicated
stacks, at this moment its undefined which values should be shown.

It's clear we need to cache more then single ioctl per LV,
but also we need to define more explicitely relation between
reported values for snapshots.

This patch is not a final state, rather a transitional step.
It should not be giving more 'worst' values then previous
many-ioctl-calls-per-lv solution.
2016-05-27 15:47:24 +02:00
80603ad49a snapshot: use seg_status for attrs 2016-05-27 15:47:24 +02:00
92eba53a79 lv: introduce lvseg_percent_with_info_and_seg_status
Add function to obtain percentage value for cache lv_seg_status.
This API is rather evolving 'middle' step as the ultimate goal
is segment API fuctionality.

But first we need to be clear at reporting level which values
are needed to be reported for which LVs and segments.
2016-05-27 15:47:24 +02:00
f7f395667e lvstatus: enhance seg_status to handle snapshot
Add more code to properly store status for snapshot segment
maintaining lvm2 fiction of COW and snapshot internal volumes.

The key issue here is however not though-through reporting
logic - as there is no single answer for whole line state.
It not counting with layer and we may need few more ioctl to
cover all reporting needs depending upon what is actually
needed.

In reality we need to 'cache' more ioctl status queries for
individual LVs and their segments (so they checked at most once).

The other 'hard' topic for conversion is mirror segment handling.

Also we definitelly need to relocate some logic into segment's methods,
yet it might be complex as we have not clear border between targets.

TODO: define more clearly how are reporting fields defined in case
we 'stack' volumes like   -   cache of stacked  thin LV snapshot origin.
2016-05-27 15:47:24 +02:00
067c0a23e5 refresh: call resume after failing suspend
lv_refresh_suspend_resume() has escaped with fail ret code
after failing suspend and could have left many volumes in suspend state.

So always unconditionally call resume also  when suspend has failed.
2016-05-27 15:47:24 +02:00
98b41db324 cleanup: drop cmd and constify lv for lv_refresh_suspend_resume()
Like with most other lv_manip* functions take just LV arg and get cmd
from embeded pointer when needed.
2016-05-27 15:47:24 +02:00
cb49ceeaba cleanup: substract integers
Instead of doing float arithmetic, do integer math first and
convert result to float.
2016-05-27 15:47:24 +02:00
1c07e67462 cache: enhance lv_cache_wait_for_clean
Handle passthrough mode when checking cache mode state explicitely.
2016-05-27 15:47:24 +02:00
0424277c00 cache: call status only on cache pool in use
Check show cache status only for cache pool in use.
2016-05-27 15:47:24 +02:00
a4f8d1165c setup_task: add with_flush
To get better control when flushing is used add extra arg when
setting up dm task.

By default now check dm device status without flush.
(At this moment this should effect only thin and cache volumes).

Also switch dev_manager_thin_pool_status() to use more
readable 'flush' parameter instead of 'no_flush'.
2016-05-27 15:47:24 +02:00
26889b3bb6 snapshot: check merging_cow is cow
Check first the LV is cow before even checking it's a merging COW.
Note: previosly merging_cow was also merging origin, so without
this explicit check it used to return '1' also when passed
LV has been merging origin.
2016-05-27 15:47:24 +02:00
e9ee2cb6b6 report: fix report copy_percent value
When mirror/raid called copy_percent function to return,
when 100% was supposed to be returned, wrong float 100.0 value
could have been reported back instead of dm_percent_t DM_PERCENT_100.

There is broken API somewhere, since the function here rely on
actively being modifid VG content even when doing 'lvs' operation.
(extents_copies)
2016-05-27 15:47:24 +02:00
780424639a Revert "libdm: trace missing settings"
This reverts commit 8fd886f735.

This was a deliberate omission because logging token-by-token metadata
parsing greatly increases the amount of logging for hardly any benefit.

In general, only LVM config file settings need to be logged, and in
places where it's considered important to log particular elements of
metadata that should be done using specific log_* lines.

This area can be revisited.
2016-05-27 14:35:11 +01:00
b762c37555 WHATS_NEW: include recent changes 2016-05-26 09:13:30 -05:00
5dc2ed0c71 vgreduce: use process_each_vg 2016-05-25 16:41:59 -05:00
2f2b3c9100 lvconvert: use process_each_lv
In the same way that process_each_vg() can be passed
a single VG name to process, also allow process_each_lv()
to be passed a single VG name and LV name to process.
2016-05-25 15:05:49 -05:00
7fffcce924 raid: Revert _lv_extend_layered_lv non-raid0 area_multiple. 2016-05-24 14:27:05 +01:00
adeb624c3b refactor: split _report fn further into init and config part 2016-05-24 10:56:57 +02:00
8c872852cd metadata: Tidy merge.c 2016-05-24 00:57:48 +01:00
498da2414b raid10: Fix new use of area multiple calc. 2016-05-24 00:41:09 +01:00
b896f7de1e raid0: Standardise meta_areas checks before access. 2016-05-23 22:55:13 +01:00
757f7d5508 test: lvmetad-disabled 2016-05-23 12:01:11 -05:00
3d3efd7ab8 test: lvmetad-pvscan-filter
update for pvscan changes
2016-05-23 12:00:25 -05:00
9b640c3684 pvscan: use process_each_vg for autoactivate
This refactors the code for autoactivation.  Previously,
as each PV was found, it would be sent to lvmetad, and
the VG would be autoactivated using a non-standard VG
processing function (the "activation_handler") called via
a function pointer from within the lvmetad notification path.

Now, any scanning that the command needs to do (scanning
only the named device args, or scanning all devices when
there are no args), is done first, before any activation
is attempted.  During the scans, the VG names are saved.
After scanning is complete, process_each_vg is used to do
autoactivation of the saved VG names.  This makes pvscan
activation much more similar to activation done with
vgchange or lvchange.

The separate autoactivate phase also means that if lvmetad
is disabled (either before or during the scan), the command
can continue with the activation step by simply not using
lvmetad and reverting to disk scanning to do the
activation.
2016-05-23 11:57:32 -05:00
55683a659f toollib: add vg name list arg to process_each_vg 2016-05-23 11:18:16 -05:00
bf8d00985a raid0: Add raid0 segment type.
This remains experimental and quite restrictive so should only be used
for testing at this stage.  (E.g. lvreduce is not supported.)
2016-05-23 16:46:38 +01:00
ad4ca55543 tools: improve error message about VG name and select 2016-05-19 15:06:56 -05:00
6247364caf tests: test change of cache mode 2016-05-19 18:40:14 +02:00
9c083d34af debug: use display_lvname
Add some tracing message
2016-05-19 18:40:14 +02:00
197066c863 lvchange: allow change of cache mode
Add support for active cache LV.
Handle --cachemode args validation during command line processing.
Rework some lvm2 internal to use lvm2 defined  CACHE_MODE  enums
indepently on libdm defines and use enum around the code instead
of passing and comparing strings.
2016-05-19 18:40:14 +02:00
8fd886f735 libdm: trace missing settings
These settings have been missed in very verbose log.
2016-05-19 18:27:34 +02:00
e8ba5c9bd4 libdm: cache status reports passthrough cache mode
Report passthrough mode instead of 'Unknown feature'.
2016-05-19 18:26:07 +02:00
e694e0896b WHATS_NEW: include recent changes 2016-05-18 09:20:52 -05:00
591ef307b3 lvm2_activation_generator: don't create full context for liblvm2app
Don't use lvm_init() to create a full command context, which
does a lot of command setup (like connecting to daemons), which
is unnecessary for simply reading a value from lvm.conf.

Passing a NULL context arg to the lvm_config_ function is now
allowed, in which case lvm.conf is read without doing lvm
command setup.
2016-05-18 09:05:26 -05:00
7fd4119d24 liblvm: allow config settings to be read without full lvm cmd
A program may be using liblvm2app for simply checking a config
setting in lvm.conf.  In this case, a full lvm context is not
needed, only cmd->cft (which are the config settings read from
lvm.conf).

lvm_config_find_bool() can now be passed a NULL lvm context
in which case it will only create cmd->cft, check the config
setting asked for, and destroy the cmd.
2016-05-18 09:04:25 -05:00
ba9b7b69d9 pvremove: allow clearing a duplicate PV
Add a special case to allow modifying a duplicate PV
to erase it with pvremove -ff.
2016-05-16 14:40:43 -05:00
e0c22df5c4 lvmetad: remove old thread locking
The old thread locking is very fine grained and complex,
and appears to have no concurrency advantage.
2016-05-16 14:38:25 -05:00
9f72a52302 lvmetad: add request level thread locking
Use an rwlock for requests that read/write cache state.
Use a mutex for requests that read/write global info.
2016-05-16 14:38:04 -05:00
7ef152c072 python: move lvm_init
Only call lvm_init() when it's needed so that simply
loading the lvm python code in another program doesn't
make that program do lvm initialization.

The version call doesn't need a handle.

The garbage collection can just do lvm_quit to destroy
the command.  The next call that needs lvm_init will
do it first.
2016-05-16 14:36:55 -05:00
57e9df7dc5 post-release 2016-05-14 02:12:23 +01:00
15ca5883fb pre-release 2016-05-14 01:57:42 +01:00
87d9406725 lib: fix init error handling
When setting up a toolcontext, the lib init function
was detecting an error when there was none, and then
it was returning an incompletely initialized cmd struct
instead of NULL.  The effect was that the lib would try
to use the uninitialized cmd struct and segfault.
This would happen if a non-fatal error occurred during
cmd setup, e.g. user permission failed on lvmetad socket,
causing cmd to fall back to scanning and not use lvmetad.

The only real error condition is when create_toolcontext
returns NULL.  If cmd is returned, the lib can use it.
2016-05-12 13:07:52 -05:00
a6203657a0 lvmetad: Fix client error when socket access fails. 2016-05-12 01:54:09 +01:00
e6cafdad36 libdm: Show lib vsn even if driver vsn unavailable. 2016-05-12 01:14:25 +01:00
b5314c2a6a device: Retry open without O_NOATIME if it fails. 2016-05-12 01:05:52 +01:00
f3d508630d test: process-each-duplicate-pvs
skip on RHEL5 where DEV_USED_FOR_LV doesn't work
because it depends on a newer bit of sysfs.
2016-05-11 09:35:42 -05:00
5c18b0ce9c refactor: separate original _report fn into _report and _do_report fn
The _report fn is getting big - separate it in two:

  - _report fn to get all the options and arguments
  - _do_report fn for reporting itself

Also, place all the variables/arguments in one structure for easier
handling of the variables around.
2016-05-10 14:00:13 +02:00
04987e7f49 post-release 2016-05-07 00:48:40 +01:00
e4caf0beeb pre-release 2016-05-07 00:36:59 +01:00
1202713f94 activation: activation check is mandatory
Make missing activation() check before calling target_persent
an INTERNAL_ERROR.
2016-05-06 16:48:16 +02:00
2842a645fd cleanup: drop tracing
When activation is disabled, avoid tracing it in cache target.
2016-05-06 16:48:16 +02:00
db606591c0 segtype: check for activation2
Previous patch 8857b22764 missed
to check for activation for raid target.
2016-05-06 16:48:16 +02:00
144169b9b7 WHATS_NEW: duplicate PVs 2016-05-06 09:30:01 -05:00
e2d823eced metadata: move warning message about repairing VG
Move the message to just before the repair is going
to happen to avoid printing the message in cases
where repair is skipped.
2016-05-06 09:00:00 -05:00
fa130722cb test: vgcfgbackup-lvm1
The lvm1 part of vgcfgbackup-usage.
2016-05-06 09:00:00 -05:00
f194d5f169 test: vgcfgbackup-usage
Split the lvm1 part into a separate test.
2016-05-06 09:00:00 -05:00
4c5ad5a04c test: vgsplit-usage
Restart clvmd between testing each mdatype to
avoid a problem with dev state being kept from
one test to the next.
2016-05-06 09:00:00 -05:00
29a8012724 test: lvmetad-ambiguous
update for duplicate changes
2016-05-06 09:00:00 -05:00
d4d1d5ac3e test: pv-duplicate-uuid
update for duplicate changes
2016-05-06 09:00:00 -05:00
708eca39ea test: process-each-duplicate-pvs
Update for new duplicate processing.
2016-05-06 09:00:00 -05:00
e84fb639f0 lvmetad: add duplicate resolution advice 2016-05-06 09:00:00 -05:00
b1ea27b1e2 lvmetad: disable if device scan fails
If a command begins repopulating the lvmetad cache,
and fails part way through, it should set the disabled
state in lvmetad so other commands don't use bad data.
If a subsequent scan succeeds, the disabled state is
cleared.
2016-05-06 09:00:00 -05:00
49d9582bed lvmcache: use active LVs and device sizes to choose between duplicates
If duplicate devices exist for a PV, and one device's
size matches the PV size, but the other doesn't, then
prefer the matching device.

If one device is used by an active LV, prefer that device.
2016-05-06 09:00:00 -05:00
d4e434d1e6 pvs: new attr and field for unchosen duplicate device
When there are duplicate devices for a PV, one device
is preferred and chosen to exist in the VG.  The other
devices are not used by lvm, but are displayed by pvs
with a new PV attr "d", indicating that they are
unchosen duplicate PVs.

The "duplicate" reporting field is set to "duplicate"
when the PV is an unchosen duplicate, and that field
is blank for the chosen PV.
2016-05-06 09:00:00 -05:00
d3d13e134a lvmcache: process duplicate PVs directly
Previously, duplicate PVs were processed as a side effect
of processing the "chosen" PV in lvmcache.  The duplicate
PV would be hacked into lvmcache temporarily in place of
the chosen PV.

In the old way, we had to always process the "chosen" PV
device, even if a duplicate of it was named on the command
line.  This meant we were processing a different device than
was asked for.  This could be worked around by naming
multiple duplicate devs on the command line in which case
they were swapped in and out of lvmcache for processing.

Now, the duplicate devs are processed directly in their
own processing loop.  This means we can remove the old
hacks related to processing dups as a side effect of
processing the chosen device.  We can now simply process
the device that was named on the command line.

When the same PVID exists on two or more devices, one device
is preferred and used in the VG, and the others are duplicates
and are not used in the VG.  The preferred device exists in
lvmcache as usual.  The duplicates exist in a specical list
of unused duplicate devices.

The duplicate devs have the "d" attribute and the "duplicate"
reporting field displays "duplicate" for them.

'pvs' warns about duplicates, but the formal output only
includes the single preferred PV.

'pvs -a' has the same warnings, and the duplicate devs are
included in the output.

'pvs <path>' has the same warnings, and displays the named
device, whether it is preferred or a duplicate.
2016-05-06 09:00:00 -05:00
8b7a78c728 lvmcache: improve duplicate PV handling
Wait to compare and choose alternate duplicate devices until
after all devices are scanned.  During scanning, the first
duplicate dev is kept in lvmcache, and others are kept in a
new list (_found_duplicate_devs).

After all devices are scanned, compare all the duplicates
available for a given PVID and decide which is best.

If the dev used in lvmcache is changed, drop the old dev
from lvmcache entirely and rescan the replacement dev.
Previously the VG metadata from the old dev was kept in
lvmcache and only the dev was replaced.

A new config setting devices/allow_changes_with_duplicate_pvs
can be set to 0 which disallows modifying a VG or activating
LVs in it when the VG contains PVs with duplicate devices.
Set to 1 is the old behavior which allowed the VG to be
changed.

The logic for which of two devs is preferred has changed.
The primary goal is to choose a device that is currently
in use if the other isn't, e.g. by an active LV.

. prefer dev with fs mounted if the other doesn't, else
. prefer dev that is dm if the other isn't, else
. prefer dev in subsystem if the other isn't

If neither device is preferred by these rules, then don't
change devices in lvmcache, leaving the one that was found
first.

The previous logic for preferring a device was:

. prefer dev in subsystem if the other isn't, else
. prefer dev without holders if the other has holders, else
. prefer dev that is dm if the other isn't
2016-05-06 09:00:00 -05:00
67da017fd2 lvmetad: remove client side altdev code
This is no longer used since lvmetad no longer
keeps track of alternate devices for duplicate PVs,
but is simply disabled when duplicates appear.
2016-05-06 09:00:00 -05:00
3d2fbfe243 lvmetad: set disabled flag when duplicate PVs are seen
When duplicate PVs are detected, set the disabled
flag so that commands will disable use of lvmetad.

This duplicate detection is done by lvmetad itself
when it's told about a single new PV with a PVID
that matches an existing PV on another device.
(This is different from the case where the command
is scanning all devices and detects the duplicate.)

Remove the "altdev" logic that attempted to keep
track of multiple devices for a single PV.  It
is no longer used since lvmetad is disabled in
this case.
2016-05-06 08:59:59 -05:00
9539ee8098 lvmetad: set disabled flag in lvmetad if duplicate PVs are found
When devices are being scanned, if duplicate PVs are seen,
tell lvmetad to set its disabled flag because of duplicate PVs.
2016-05-06 08:59:59 -05:00
a1dbd54885 pvscan: fix errors for single dev scan while lvmetad is disabled
While lvmetad was disabled, 'pvscan --cache dev' would produce
confusing error messages.
2016-05-06 08:59:59 -05:00
08aeea6a12 tests: do not use EPOCH for get wrapper
Avoid poluting filesystem with debug.log_DEBUG for get wrapper
2016-05-05 23:55:20 +02:00
07c1694ff5 tests: update aux raid support
For raid1  use chunksize as bitmap-chunk specification.
Always enforce usage of bitmap - getting comparable outcome
as lvm2 raid support uses.
Add udev_wait after stopping  md array - as in fact leg-device
are still in use by target even command has finished.

(mdadm --stop causes WATCH rule wakeup, and
ioctl(STOP_ARRAY) returns IMHO to early - it should finish
and fsync work on leg devices first).
2016-05-05 23:55:20 +02:00
7bb39af036 tests: check default policy is used when unspecified
If the policy is not given with policy settings we assume
the default one is going to be used - it's users responsibility
to pair them properly.
2016-05-05 23:55:20 +02:00
95f0e25601 tests: check for thin tools
Test needs repair utils to be available.
2016-05-05 23:55:20 +02:00
673d4f7453 cleanup: use unsigned with EPOCH printf format 2016-05-05 23:55:20 +02:00
ed9162cd88 cleanup: enhance warning message
Add WARNING: for log_warn.
Show device name which is marked missing.
2016-05-05 23:55:18 +02:00
f6575ec824 cleanup: just switch error path
Check for error case in if() like we normally do.
Let code continue on success.
2016-05-05 23:52:06 +02:00
d1ecbfa52d lvcreate: improve --chunksize support for cached volume.
Support parsing --chunksize option also when converting.
Now user can use cache pool created with i.e. 32K chunksize,
while in caching user can select 512K blocks.
Tool is supposed to validate cache metadata size is big enough
to support such chunk size. Otherwise error is shown.
2016-05-05 23:50:10 +02:00
d3b15674df lvcreate: check for lv type and created segtype
When creating LV - in some case we change created segment type
(ATM for cache and snapshot) and we then manipulate with
lv segment according to 'lp' segtype.
Fix this by checking for proper type before accessing segment members.

This makes command like:

lvcreate --type cache-pool -L10 vg/cpool
lvcreate -H -L10 --cachesettings migtation_threshold=10000  vg/cpool

to pass since now tool correctly selects default cache policy.
2016-05-05 23:34:35 +02:00
d0111563c2 debug: enhance debug msg for cache 2016-05-05 23:34:35 +02:00
fd79027cae cache: use target_present_version
Using new function.
Also add trace for error path.
2016-05-05 23:34:35 +02:00
4d116d7a28 cleanup: gather version info with single check
As we already collect version info anyway, allow to use it through
a single call (can makes logs shorter and saves ioctl).
2016-05-05 23:34:30 +02:00
def65507e6 cache: add cache_set_params function
Wrapping function to handle setup of various cache related params.
Reusable with lvcreate & lvconvert.
2016-05-05 23:30:49 +02:00
ae805eea50 cache: add validate_lv_cache_chunk_size 2016-05-05 23:30:49 +02:00
00dfca034c cache: function for min metadata size estimation
Move min code into reusable function.
2016-05-05 23:30:02 +02:00
7c1e601164 pvcreate: improve debug message
state what the printed UUID is.
2016-05-04 12:11:13 -05:00
1df6769aca pvcreate, pvremove: translate arg name to device once
Rather than doing repeated translations from name to
device when comparing args to existing PVs, do one
translation of the arg names and saving the device,
before checking existing PVs.
2016-05-04 11:28:28 -05:00
795e47cec5 post-release 2016-04-30 01:12:33 +01:00
e53ecf91f7 pre-release 2016-04-30 01:07:26 +01:00
c76df666c9 raid: Use inherited tags when wiping rmeta.
If there's an activation volume_filter, it might not be possible
to activate the rmeta LVs to wipe them.  At least inherit any
LV tags from the parent LV while attempting this.
2016-04-29 19:49:21 +01:00
e3efcdc9f5 datastruct: Add str_list_wipe. 2016-04-29 19:47:15 +01:00
16019b518e libdm: Add dm_udev_wait_immediate.
dm_udev_wait() waits inside the library.
dm_udev_wait_immediate allows the caller to do other things if the
cookie isn't yet ready to be decremented.
2016-04-28 00:54:27 +01:00
a2d2a61339 pvscan: autoactivation should ignore some VGs
pvscan autoactivation has its own VG processing implementation,
so it can't properly handle things like foreign or shared VGs,
so make it ignore those VG types (or errors from them) as best
as possible.

Add a FIXME stating that pvscan autoactivation must really be
moved to the standard VG processing by calling process_each_vg
to do activation once the scanning / cache update is finished.
2016-04-27 15:45:38 -05:00
263c1a4db5 lvmetad: improve warning after lvmetad message fails
Make it more consistent with the other similar warning.
2016-04-27 15:38:34 -05:00
3c53acb378 metadata: fix segfault when filters reject devices
Checking for devices uses is_missing_pv() to check
if there is a device for the PV.  is_missing_pv()
is based on the MISSING_PV flag, which does not
always correspond to !pv->dev.  When using lvmetad,
a command like:

pvs --config 'devices/filter=["a|/dev/sdb|", "r|.*|"]'

will cause a number of PVs to have NULL pv->dev, but
not the MISSING_PV flag.  So, NULL pv->dev needs to
also be checked.
2016-04-27 12:13:26 -05:00
49f32e4859 cache: better support for alias check
To still support disabling of policies for test we need
better logic for alias detection introduced in
588455d03e.
2016-04-27 00:20:37 +02:00
2a2efab0b1 cleanup: use log_debug_activation 2016-04-27 00:01:08 +02:00
c81005dcc4 cleanup: smaller timeout
1s -> 0.5s
Also indent fix.
2016-04-26 23:59:20 +02:00
07d92322c1 man: lvcreate doc passthrough
Add few more words about passthough mode.
2016-04-26 23:29:58 +02:00
d90d99b23d man: lvchange updates
Drop never existing --degrade.
2016-04-26 23:29:58 +02:00
e77b6968b6 lvchange: use better arg functions 2016-04-26 23:29:58 +02:00
c215e1be5c lvchange: always check for sigint
Check sigint() state during process_each_lv.
2016-04-26 23:29:08 +02:00
d8bdc7af37 lvchange: fix return code
We already opened VG for this - so not an invalid cmdline.
2016-04-26 23:28:01 +02:00
84a5b19539 thin: zero and transaction_id also with thin volumes
Show trasaction_id when thin volume was created.
Also show zeroing state of thin-pool with thin volume (so user
doesn't need to lookup thin-pool).
2016-04-26 23:24:51 +02:00
8b5967e1e3 cache: check for clean cache as separete function 2016-04-26 23:24:17 +02:00
588455d03e cache: with cache target 1.9 mq is alias to smq
Avoid useless check for mq policy, it's loaded as smq
and aliased.
2016-04-26 23:24:05 +02:00
aa91fe3d3c modprobe: check /sys/module entry first
Before executing modprobe for given module name, just check
if the module is not already present in /sys/module.

Useful when checking dm-cache-policy modules as we do not
having matching interface like for targets.
2016-04-26 23:23:03 +02:00
ecae76c713 udev: rules: add comments explaining subsystem-specific rules 2016-04-26 12:57:37 +02:00
2bb33aaf55 udev: rules: remove mpath from 10-dm.rules, superseded by 11-dm-mpath.rules (mpath>=0.6.0)
Multipath 0.6.0 contains new 11-dm-mpath.rules which supersede the rule
that was in 10-dm.rules. The 11-dm-mpath.rules are also more complete,
fixing several other issues. Using the new 11-dm-mpath.rules from
multipath-tools >= 0.6.0 is strongly recommended for proper
DM multipath functionality!

See also:
  http://christophe.varoqui.free.fr
  http://git.opensvc.com/gitweb.cgi?p=multipath-tools/.git;a=blob;f=multipath/11-dm-mpath.rules
2016-04-25 14:55:54 +02:00
379874a2d0 cleanup: do not mention segment in warning message if device not found for a PV when checking used/assumed devs for an LV
[0] fedora/~ # pvs --config 'devices/filter=["a|/dev/sda|", "r|.*|"]'
  WARNING: Device for PV Qcxpcy-XgtP-UD3s-PmG0-qLyE-Z0ho-DYsxoz not found or rejected by a filter.
  WARNING: Device for PV Qcxpcy-XgtP-UD3s-PmG0-qLyE-Z0ho-DYsxoz not found or rejected by a filter.
  WARNING: Couldn't find device for segment belonging to fedora/root while checking used and assumed devices.
  WARNING: Couldn't find device for segment belonging to fedora/swap while checking used and assumed devices.
  PV         VG     Fmt  Attr PSize   PFree
  /dev/sda          lvm2 ---  128.00m 128.00m
  [unknown]  fedora lvm2 a-m   19.49g      0

Probably not worth mentioning "segments" here, just state that devices
for an LV can't be all found during the check - it's less mysterious for
user then:

[0] fedora/~ # pvs --config 'devices/filter=["a|/dev/sda|", "r|.*|"]'
  WARNING: Device for PV Qcxpcy-XgtP-UD3s-PmG0-qLyE-Z0ho-DYsxoz not found or rejected by a filter.
  WARNING: Device for PV Qcxpcy-XgtP-UD3s-PmG0-qLyE-Z0ho-DYsxoz not found or rejected by a filter.
  WARNING: Couldn't find all devices for LV fedora/root while checking used and assumed devices.
  WARNING: Couldn't find all devices for LV fedora/swap while checking used and assumed devices.
  PV         VG     Fmt  Attr PSize   PFree
  /dev/sda          lvm2 ---  128.00m 128.00m
  [unknown]  fedora lvm2 a-m   19.49g      0
2016-04-25 11:44:24 +02:00
9d976c0002 metadata: log warning instead of error if device not found while checking used and assumed devs
When checking assumed PVs against real devices used for LVs and if
there's no device assigned for an assumed PV (e.g. due to filters),
do log_warn instead of log_error and continue checking LV segments
and associated assumed PVs further, just like we do log_warn elsewhere
in this situation.

This way user will see the warning for each LV which couldn't be
checked completely against real PVs used. Before, we logged only
the very first occurence of missing device for an LV in a VG and we
returned from the function doing this check for all the LVs in VG
immediately which may be a bit misleading because it didn't tell
user about all the other LVs and whether they could be checked
or not.

For example, we have this setup:

[0] fedora/~ # pvs
  PV         VG     Fmt  Attr PSize   PFree
  /dev/sda          lvm2 ---  128.00m 128.00m
  /dev/vda2  fedora lvm2 a--   19.49g      0

[0] fedora/~ # lvs -o+devices
  LV   VG     Attr       LSize   Devices
  root fedora -wi-ao----  19.00g /dev/vda2(0)
  swap fedora -wi-ao---- 500.00m /dev/vda2(4864)

Before this patch (only the very first LV in a VG is logged to have a
problem while checking used and assumed devices):

[0] fedora/~ # pvs --config 'devices/filter=["a|/dev/sda|", "r|.*|"]'
  WARNING: Device for PV Qcxpcy-XgtP-UD3s-PmG0-qLyE-Z0ho-DYsxoz not found or rejected by a filter.
  WARNING: Device for PV Qcxpcy-XgtP-UD3s-PmG0-qLyE-Z0ho-DYsxoz not found or rejected by a filter.
  Couldn't find device for segment belonging to fedora/root while checking used and assumed devices.
  PV         VG     Fmt  Attr PSize   PFree
  /dev/sda          lvm2 ---  128.00m 128.00m
  [unknown]  fedora lvm2 a-m   19.49g      0

With this patch applied (all LVs where we hit problem while checking
used and assumed devices are logged and it's warning, not error):

[0] fedora/~ # pvs --config 'devices/filter=["a|/dev/sda|", "r|.*|"]'
  WARNING: Device for PV Qcxpcy-XgtP-UD3s-PmG0-qLyE-Z0ho-DYsxoz not found or rejected by a filter.
  WARNING: Device for PV Qcxpcy-XgtP-UD3s-PmG0-qLyE-Z0ho-DYsxoz not found or rejected by a filter.
  WARNING: Couldn't find device for segment belonging to fedora/root while checking used and assumed devices.
  WARNING: Couldn't find device for segment belonging to fedora/swap while checking used and assumed devices.
  PV         VG     Fmt  Attr PSize   PFree
  /dev/sda          lvm2 ---  128.00m 128.00m
  [unknown]  fedora lvm2 a-m   19.49g      0
2016-04-25 11:27:28 +02:00
eb8edccd58 post-release 2016-04-23 00:43:13 +01:00
546b2006dd pre-release 2016-04-23 00:41:55 +01:00
31b11d0228 tests: drop cluster testing with pvmove
Unwanteadly enabled in previous check-in.
2016-04-22 14:15:36 +02:00
a88828c845 coverity: check for sys error in clock call 2016-04-22 14:15:36 +02:00
bc239f15eb coverity: ignore some dm_strncpy results
Using them only for debug so ignorable.
Also don't mark stack char buffer alignment, compiler already knows
what's the best here.
2016-04-22 14:15:36 +02:00
d12ba022c8 coverity: keep expression using 64bit
Use 64bit input to remain with whole evaluation in 64bit.
2016-04-22 14:15:36 +02:00
d564d9f39c coverity: is_used_pv needs valid pv pointer 2016-04-22 14:15:36 +02:00
2dc6b97856 tests: make test independent on usage [] for hidden LVs 2016-04-22 12:53:09 +02:00
4ddf5a11cf cache: fix previous change and correct ()
412f09ca33 missed parentheses.
2016-04-22 12:52:53 +02:00
17ad884836 libdm-stats: check for empty region and area lists
Check that @stats_list and @stats_print returned data in the
_stats_parse_list() and _stats_parse_region() functions before
attempting to operate on region and area values.

This avoids a coverity warning since fgets() could potentially
return no data from the memory buffer returned by the ioctl.

In both cases the ioctl would return an error, preventing these
functions from running, however it is cleaner to test for the
condition explicitly and fail in those cases.
2016-04-22 10:35:07 +01:00
69c2f56005 tests: keep using [] for hidden volumes
Figure out which test needs to see hidden volumes without [].
But normally use [] for debug printing in tests.
It's confusing otherwise.
2016-04-22 01:14:56 +02:00
8c4b717f4d coverity: drop abadoing object
As mempool is destroyed on by caller don't bother for
mempool freeing here.
2016-04-22 01:13:35 +02:00
0bf5518626 coverity: avoid using signed types for single bits 2016-04-22 01:12:34 +02:00
412f09ca33 coverity: return non-null string with internal error
While we return internal error we should not let tool crash on NULL
access, so return valid string for such case.
2016-04-22 01:12:34 +02:00
447daa9179 coverity: use wider type for whole expression
Coverity likes when the types are same through the whole expression.
And since dev_t is 64b - widen int type early.
2016-04-22 01:12:34 +02:00
edcb3e65c6 coverity: drop unused header file 2016-04-22 01:12:34 +02:00
99e96f3ce9 coverity: fix error paths
Patch 74e704bb44 missed to update
error path. Since now we just need to 'return_0' as 'dmt is NULL
and thus may not be destroyed.
2016-04-22 01:12:34 +02:00
cbf99be43a coverity: fix memory access
Commit  52e0d0db44 introduced regression
as code may access   buf[0 - 1].

Reorder code to first remove '\n' and then check buffer size for
empty.
2016-04-22 01:11:57 +02:00
556eba1835 cleanup: use kdev_t header in lvm tree
Reuse libdm header in lvm so we have single definition
of MAJOR/MINOR/MKDEV macros in use.
2016-04-22 00:23:28 +02:00
9d4f9defc3 cleanup: simplify code
dm_strncpy() also check the size fits.
2016-04-22 00:22:02 +02:00
c9373a0c2a WHATS_NEW: disable lvmetad for lvm1 2016-04-21 16:40:44 -05:00
01181a299e activate: Hide errors when snapshot merge delayed. 2016-04-21 22:14:10 +01:00
4d095c2fbb poll daemon: only call lvmetad_connect when needed
When lvm is not using lvmetad, the lvmetad_connect()
in the forked polling process is not needed and was
generating unwanted warnings.
2016-04-21 15:58:34 -05:00
11dd362454 tests: GLIBC decided to obsolete readdir_r
Keep the code compilatible without warnings on newer glibc.
2016-04-21 17:48:19 +02:00
1134ab6324 lvmetad: warn about making changes while not using lvmetad
If lvmetad is running, and a command opts to not use it
(--config global/use_lvmetad=0), and the command changes
metadata, then the metadata change is not visible to
lvmetad.  Subsequent commands using lvmetad to change
metadata may cause corruption based on the invalid
lvmetad state.

Eventually we can set the disabled state in lvmetad
to prevent this problem, but for now print a warning
about the possibility.
2016-04-21 10:28:01 -05:00
6e6f8025ff lvmetad: fix compile without lvmetad
Last commit was missing stub function.
2016-04-21 10:06:47 -05:00
e44c4806db lvmetad: check pid for warning case
When command is not using lvmetad because
use_lvmetad=0 in the config, but the lvmetad
pidfile exists, print a warning (previously
this checked for the socket existing instead
of the pidfile existing.)
2016-04-21 09:50:59 -05:00
d00b70c789 lvmetad: check for socket in connect
We can connect if the socket is present, even
though the pidfile may not exist, since systemd
may start the process when the socket is opened.
2016-04-21 09:27:20 -05:00
0778d2e985 display: Avoid internal snapshot LV names in msgs.
vg/snapshotN should not appear anywhere.

No code should be showing this, but it was noticed in some logs last
week and we can deal with it in display_lvname().
2016-04-21 00:30:17 +01:00
2763b928de lvmetad: fix compilation without lvmetad# 2016-04-21 00:34:01 +02:00
7ce486e881 tests: minor update 2016-04-21 00:34:01 +02:00
545b58542c tests: still show systems stas when command has not produced debug.log file
When no debug.log* file is present whole stacktracking was skipped.
Add extra test the file exists to catch this case.
2016-04-21 00:34:01 +02:00
22a71e1119 tests: document make parametr for tracing aux scripts 2016-04-21 00:34:01 +02:00
509b2e5247 debug: move misplaced log_debug
It should log action before taking it instead of only in error path.
2016-04-21 00:34:01 +02:00
57f468a53e configure: respect --disable-lvmetad/lvmpolld
When user requested on cmdline disabling of lvmetad/lvmpoll,
respect it and when lvmlockd requires these daemon,
Error configure with clear message about misconfiguration.
2016-04-21 00:34:01 +02:00
600d7ca15f configure: detect for /var/lock dir
Detecs systems with /run/lock dir and use such path directly instead
of /var/lock.
2016-04-20 23:32:51 +02:00
5c104c5de9 lvmetad: connect from forked polling process
With commit 5e9e43074a, lvmetad connections are
now made explicitly, so a new connection must be
created from a child created for polling.
2016-04-20 09:04:39 -05:00
9553260673 test: lvmetad-override
Fix test case where a warning appears when it's not expected.
2016-04-19 14:26:05 -05:00
5e9e43074a lvmetad: rework command connection setup and checking
The lvmetad connection is created within the
init_connections() path during command startup,
rather than via the old lvmetad_active() check.

The old lvmetad_active() checks are replaced
with lvmetad_used() which is a simple check that
tests if the command is using/connected to lvmetad.

The old lvmetad_set_active(cmd, 0) calls, which
stopped the command from using lvmetad (to revert to
disk scanning), are replaced with lvmetad_make_unused(cmd).
2016-04-19 14:00:02 -05:00
593900b795 lvmetad: use defines for disabled reason strings 2016-04-19 11:45:24 -05:00
fa904a844f test: lvmetad-warning
The test was a weak attempt at verifying the special
combination of lvchange/vgchange -aay --sysinit, but
was only looking for lvmetad connection warnings.

Update the warning checks, and check the LV activation
state directly which is the main point.

Rename the test to reflect its purpose of checking
the -aay --sysinit combination.
2016-04-19 11:45:24 -05:00
6b1c0a4190 test: lvmetad-override 2016-04-19 11:45:24 -05:00
c5cd5b4b69 test: lvmetad-no-cluster
Update warning message check
2016-04-19 11:45:24 -05:00
a5722ed7e7 test: update lvmetad-disabled
Update the check about lvmetad running but not used.

Also add tests related to the new lvmetad disabled state.
lvm1 metadata is used here to test the disabled state
because lvm1 metadata is the first condition using the
disabled state.
2016-04-19 11:45:24 -05:00
c9cf85f606 test: update lvm1 test
Make it a generic lvm1 test, which should work
with or without lvmetad now that lvmetad is just
disabled when lvm1 is used.
2016-04-19 11:45:19 -05:00
2a17610899 lvmetad: disable if command uses lvm1
Alternatively, a command could return an error saying
that lvm1 and lvmetad are not compatible.
2016-04-19 09:41:18 -05:00
1e380864e5 lvmetad: clear the disabled flag in lvmetad
After a device rescan that repopulates lvmetad,
if no reason for disabling lvmetad was seen
(lvm1 metadata or duplicate PVs), then clear
the disabled flag in lvmetad.  This allows
commands to resume using the lvmetad cache
after the cause for disabling it has been removed.
2016-04-19 09:41:18 -05:00
04a83148ce lvmetad: use the disabled flag in commands
Commands already check if the lvmetad token is valid,
and if not, they rescan devices to repopulate lvmetad
before running.  Now, in addition to checking the
lvmetad token, they also check if the lvmetad disabled
flag is set.  If so, they do not use the lvmetad cache
and revert to disk scanning.
2016-04-19 09:41:18 -05:00
ff867c2ef6 lvmetad: set disabled flag in lvmetad if lvm1 metadata is found
When devices are being scanned, if lvm1 metadata is seen,
tell lvmetad to set its disabled flag because of lvm1 metadata.
2016-04-19 09:41:18 -05:00
a4ef8fa25e lvmetad: add disabled state
A global flag in lvmetad indicates it has been disabled.
Other flags indicate the reason it was disabled.
These flags can be queried using get_global_info.

The lvmetactl debugging utility can set and clear the
disabled flag in lvmetad.  Nothing else sets the
disabled flag yet.

Commands will check these flags after connecting to
lvmetad.  If the disabled flag is set, the command
will not use the lvmetad cache, but revert to disk
scanning.

To test this feature:

$ lvmetactl get_global_info
response = "OK"
global_invalid = 0
global_disable = 0
disable_reason = "none"
token = "filter:3041577944"

$ vgs
(should report VGs from lvmetad)

$ lvmetactl set_global_disable 1

$ lvmetactl get_global_info
response = "OK"
global_invalid = 0
global_disable = 1
disable_reason = "DIRECT"
token = "filter:3041577944"

$ vgs
  WARNING: Not using lvmetad because the disable flag was set directly.
(should report VGs without contacting lvmetad)

$ lvmetactl set_global_disable 0

$ vgs
(should report VGs from lvmetad)
2016-04-19 09:41:18 -05:00
e41ee70acc toollib: remove unneeded call in process_each_pv
process_each_pv was doing:

1. lvmcache_seed_infos_from_lvmetad()
   sends pv_list request to lvmetad.

2. get_vgnameids()
   sends vg_list request to lvmetad.

3. _get_all_devices()
   first calls lvmcache_seed_infos_from_lvmetad(),
   which is a no-op if it's already been called.

Because get_vgnameids() does not use the information
from lvmcache_seed_infos_from_lvmetad(), it does not
need to be called prior to get_all_devices where
it is actually needed.
2016-04-19 09:40:24 -05:00
a6a32a7c0e metadata: don't repair shared VGs
When the in-use flag looks like it needs to be repaired.
2016-04-19 09:19:32 -05:00
a400eba174 lvmlockd: skip unnecessary lvmetad cache update
In cases where a VG is reread from disk, but the
seqno matches what is currently in lvmetad, the
metadata in lvmetad doesn't need to be updated.
2016-04-19 09:19:32 -05:00
50633039bf tests: use should for failing test
It's better to use 'should' for failing test before it gets fixed,
when we ignore failing result.
2016-04-18 23:12:05 +02:00
59b0bd7b64 tests: use bigger raid size
To avoid problem with report of array in-sync use for now bigger
raid size 64M.
2016-04-18 23:09:17 +02:00
88c19d5d72 lvchange: improve refresh for merging thin volume
When running lvchange --refresh on merging thin volume,
try to deactivate snapshot thinLV in case it's preventing
startup of merge process.
2016-04-18 23:05:51 +02:00
7e5881dd13 snapshot: improve merge
Improve code for snapshot merge for readabilty
and also reduce number of tests needed to decide
if merging can or cannot be started.

(Further improving 9cccf5245a)
2016-04-18 23:05:17 +02:00
d1c1f60047 debug: use display_lvname 2016-04-18 12:32:56 +02:00
e2ceb90095 debug: update message in libdm
When dm_tree_find_node_by_uuid() fails to find passed uuid,
report in lof_debug the complete original uuid,
not the one stripped of LVM- prefix.

TODO: inspect manipulation with LVM- prefix here.
2016-04-18 12:32:56 +02:00
f5cf6cc9ed debug: fix error message
log_error is replaced with warn since the result
of function is not result in command error.
2016-04-18 12:32:56 +02:00
9cccf5245a thin: improve recognizing of merge in progress
Rewrite too condensed condition in more readable form,
wher decision are clearly separated and commented and
also add debug messages for them.
2016-04-18 12:32:52 +02:00
e2cd882f2e thin: check runtime table line for merging
To recognize in runtime if we are merging or not
to make consistent decision between suspend and resume
add function to parse thin table line when add
merging thin device to the table.
2016-04-18 11:18:35 +02:00
662090e358 tests: fix check_lvmlockd_test 2016-04-15 12:35:20 -05:00
6954de22e2 activate: Improve snapshot merge initiation
A snapshot merge into its origin cannot be initiated while the devices
are in use.  If there is outside interference (such as from udev),
the suspend (preload) and resume stages can reach conflicting decisions
about whether or not to proceed.

Try to make the logic more robust by checking the inactive or live
table during resume.  (This is still not perfect.)
2016-04-15 02:33:38 +01:00
150cff9cce activation: Log when pending snap merge postponed. 2016-04-14 23:42:56 +01:00
7ae5f6fc5c WHATS_NEW for lvmetad scanning changes 2016-04-14 16:55:34 -05:00
ff09bda7d5 activation: Add LV name to a debug message. 2016-04-14 22:41:25 +01:00
f0179fac31 snapshot: Don't deactivate fictional snapshot LV.
Commit 971ab733b7 ("thin: activation of
merging thin snapshot") also added an incorrect deactivation attempt
for non-thin LVs: find_snapshot(lv)->lv is not designed to be
activated and any attempt to deactivate it is incorrect.
2016-04-14 22:32:26 +01:00
c68fb55ac1 toollib: Fix misleading message when forking.
Commands like pvscan --background run entirely in the background,
but others fork only for polling.
2016-04-14 17:21:02 +01:00
3f6e7f90ca refactor: factor out vg/lv/pv handling part from report_for_selection fn
Functionality will be reused by future patches. Also, it makes the code
more readable.
2016-04-14 15:24:36 +02:00
9a299d2d7a tests: lvmetad-lvm1 fix
workaround this test failure until the proper
lvmetad/lvm1 fixes arrive shortly.
2016-04-13 15:07:53 -05:00
579bd92009 lvmetad: add FIXME to comment 2016-04-13 14:08:29 -05:00
56c68b3476 lvmetad: preemptively check and rescan in commands
Move checking the lvmetad state, and the possible rescan,
out of lvmetad_send() to the start of the command.

Previously, the token mismatch and rescan would occur
within lvmetad_send() for some other request.  Now,
the token mismatch is detected earlier, so the
rescan can be done before the main command is in
progress.  Rescanning deep within the processing of
another command will disturb the lvmcache state of
that other command.

A rescan already exists at the start of the command
for the case where foreign VGs are going to be read.
This same rescan is now also performed when there is
an lvmetad token mismatch (from a changed global_filter).

The commands pvscan/vgscan/lvscan/vgimport are excluded
from this preemptive checking/rescanning for lvmetad
because they want to do rescanning themselves explicitly.

If rescanning devices fails, then lvmetad has not been
correctly repopulated and should not be used, so make
the command revert to not using lvmetad.
2016-04-13 14:05:42 -05:00
a28c81cbae debug: unify some tracing messages
Introduce  FMTVGID - although it might be possibly better to ensure
vgid is always \0 ended string.

Unify some lvmcache reported messages.
2016-04-12 13:06:16 +02:00
1be74cfd7f cleanup: gcc warn about comparing int with uint 2016-04-12 11:47:51 +02:00
0f7975cb35 cleanup: avoid declaring var in the middle of code
Easier to read code.
2016-04-12 11:47:51 +02:00
147c9c01a2 rename function read_vgname to read_vgsummary
The name did not clearly represent what it does.
2016-04-11 13:07:48 -05:00
fe65a86cbc devcache: do not insert devices without device node
When not obtaining device from udev, we are doing deep devdir scan,
and at the same time we try to insert everything what /sys/dev/block
knows about. However in case  lvm2 is configured to use nonstardard
devdir this way it will see (and scan) devices from a real system.

lvm2 test suite is using its own test devdir with its
own device nodes. To avoid touching real /dev  devices, validate
the device node exist in give dir and do not insert such device
into a cache.

With obtain list from udev this patch has no effect
(the normal user path).
2016-04-11 10:33:14 +02:00
07a60b59f7 devcache: index devices also without udev
We have _insert_dirs() for  udev and non-udev compilation.
Compiling without udev missed to call dev_cache_index_devs().
Move the call after _insert_dirs() call so both compilation
gets it.
2016-04-11 10:32:19 +02:00
9e14abb887 post-release 2016-04-09 02:10:39 +01:00
3aab784aa5 pre-release 2016-04-09 02:08:44 +01:00
af148a9d77 cleanup: avoid gcc warns
Some older systems may had global declaration to cause gcc warning.
Rename for cases we don't care...
2016-04-08 20:20:16 +02:00
5cfa6cb347 cleanup: simplier to read condition
Make more readable what we are looking for and just test for
KERNEL version at one place.
2016-04-08 20:20:16 +02:00
74e704bb44 cleanup: reuse _setup_task
Shorten code and use common code from _setup_task.
Reorder naming of major:minor sscanf (as later it's been
also used swapped there was no real bug).
2016-04-08 20:20:16 +02:00
a09d65891f dev_manager: device_is_usable does not flush
When scanning if device is being usable as PV,
we call STATUS - but this status should not cause
any flushing.
Skip also open_count information as it's not needed.
2016-04-08 20:20:04 +02:00
f40dfb48ad activation: Skip another non-prefixed info ioctl.
_percent() also does a lookup by dm uuid.
Also get kernel version from cmd->kernel_vsn.
2016-04-08 16:27:12 +01:00
e6768997e1 test: Fix testing of installed lvmdbusd
If lvmdbusd is missing expression triggers ERR trap instead of skipping
the test.
2016-04-08 16:26:25 +02:00
ed0c779bd1 report: remove superfluous SEGSSTATUS report type
We don't have any report field of this type yet. Return this patch into
the play if we really need that. Currenly we always report status
(result of "status" dm ioctl) for an LV as a whole where we choose
segment which represents the LV, not calling status for each possible
segment it contains - we don't need this now so I'm removing it to
not make the code more complex uselessly.
2016-04-08 14:21:47 +02:00
50866034a2 cleanup: use common init/destroy_processing_handle in _report fn and cleanup error paths 2016-04-08 11:01:19 +02:00
f2e59e05ed cleanup: use #define for field's quote and pair character and also for the error msg while extending output line 2016-04-08 10:55:13 +02:00
248f47d489 tests: require newer cache target
Older cache target is likely not updating status at all...
2016-04-08 00:04:26 +02:00
9ab53dddf5 tests: use mkfs.ext3
mkfs.ext4 is not really needed so use more widespread mkfs.ext3
so test runs on older system.
2016-04-07 22:32:09 +02:00
8b2108e6b1 activation: do not check for devs without LVM-
Devices without "LVM-" uuid prefix have been generated by very old
version of lvm2 2.00 and 2.01.
Since version 2.02 all lvm2 devices are using prefix "LVM-".

However checking for present of ancient non prefixed devices does
take extra IOCTL per every call and for majority of todays user
it will not find anything new.

So use the assumption that users with kernel 3.X and newer are not
really using such old versions of lvm2 (year <2005) and with their
new kernel they are also using new version of lvm2 and skip
checking for them.

This change also makes trace logs more readable.
2016-04-07 22:32:08 +02:00
097a724bda lvcreate: %FREE -> %PVS
This is hotfix for RHBZ: https://bugzilla.redhat.com/1324537
However already the %FREE is not a good fit and we need something
better. Meanwhile make  -l%PVS work at least as good as %FREE
for thin-pool.

TODO: this needs rework - it should be allocator to do all the size
decisions at one place.
2016-04-07 22:32:08 +02:00
e2d4f53c82 WHATS_NEW: update
doc for previous commits.
2016-04-07 22:31:40 +02:00
7dcbf1dfd0 libdm: Correct typo. 2016-04-07 01:51:09 +01:00
f19ec0e36d lvmdump: If dir exists check dir perms too. 2016-04-06 22:56:45 +01:00
55001ae9ec lvmdump: Allow dir to exist already if it is empty 2016-04-06 22:36:42 +01:00
307ab2c179 tests: do not break teardown on failing losetup
Ignore failing 'losetup -d' - i.e. device may have disappeared...
2016-04-06 11:54:37 +02:00
07c25429e2 tests: verify repair of failing mirror
Improved test script to verify lost mirror image does not
cause mirror corruption while mirror is in use.

TODO: add more cases (lost mlog...), lost image from 3leg mirror...
2016-04-06 11:54:36 +02:00
9be7bca4be cleanup: indent 2016-04-06 11:31:02 +02:00
0584e85736 lvconvert: show percent with %.2
lvm2 shows percent values with 2 decimal digits elsewhere so use
it consistently also for this output.
2016-04-06 11:31:02 +02:00
261a85ced9 libdm: improve debug message with ioctl
Make the debug message a less difficult to read:
Ioctl shows  [ noopencount flush ] instead of cryptic [NF].
2016-04-06 11:31:02 +02:00
5b2227c2c1 preload: preserve flushing state
When leaving preload routine it should not altet state of flush required
when it's been already set to 1 and drop it to 0.

The API here is unclean, but current usage expects the same
variable pointer is for all preload calls and combines 'flush_required'
across all of them.
2016-04-06 11:31:02 +02:00
7c1937f8df suspend: fix suspend with noflush limitation
Commit 844b009584 tried to move
limit for usage of noflush to 'preload' however this was not
correctly processed.

Intead explicitly check for which types we do not want noflush
and also add debug message in this case.
2016-04-06 11:31:02 +02:00
d4c03cf7b2 mirror: fix flushing for mirror target
Fix regression caused by commit ba41ee1dc9.
The idea was to use no_flush for changed device only for thin volumes
and thin pools but also to merge this with change made in commit
844b009584.

However the resulting condition has caused misbehavior for the mirror
suspend - as that has been before the ONLY allowed target type
that could have been suspended with noflush.

Result was badly working repair for --type mirror that has been
passing 'flush' to the repaired mirror target whenever preload
wrongly set flush_required.

The origin code has required the flush_required to be set whenever
deivce size is changed.

Now it first detects if device size got smaller
'dm_tree_node_size_changed(root) < 0' - this requires flush.
Otherwise it checks device is not thin volume nor thin pool and its
size has changed (got bigger) and requires flush.

This mean upsize of thin-pool or thin volume will not require flush.
2016-04-06 11:31:02 +02:00
76fc41fb9d post-release 2016-04-01 20:36:40 +01:00
2d0d58b867 pre-release 2016-04-01 20:29:52 +01:00
60befab773 Revert "thin: display highest mapped sector"
This reverts commit fc7dacaa4c.

Let's put this information into a separate field.  It doesn't meet the
definition of the existing field.
2016-04-01 20:09:38 +01:00
42f04a0f77 dev-cache: skip VGID/LVID indexing if /sys/dev/block is not present
/sys/dev/block is available since kernel version 2.2.26 (~ 2008):
https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-dev

The VGID/LVID indexing code relies on this feature so skip indexing
if it's not available to avoid error messages about inability to open
/sys/dev/block directory.

We're not going to provide fallback code to read the /sys/block/
instead in this case as that's not that efficient - it needs extra
reads for getting major:minor and reading partitions would also
pose further reads and that's not worth it.
2016-04-01 17:09:15 +02:00
9f28eb4c20 fix: make udev_get_library_context available also for non-udev compilations
If compiling without udev_sync support, udev_get_library_context simply
returns NULL so we don't need to remember putting ifdef UDEV_SYNC_SUPPORT
in the code all the time we just need to check whether there's any udev
context initialized or not.
2016-04-01 15:35:22 +02:00
15d1824fac dev-cache: iterate devices in sysfs for VGID/LVID index if obtain_device_list_from_udev=0
If obtain_device_list_from_udev=0, LVM can make use of persistent .cache
file. This cache file contains only devices which underwent filters in
previous LVM command run. But we need to iterate over all block devices
to create the VGID/LVID index completely for the device mismatch check
to be complete as well.

This patch iterates over block devices found in sysfs to generate the
VGID/LVID index in dev cache if obtain_device_list_from_udev=0
(if obtain_device_list_from_udev=1, we always read complete list of
block devices from udev and we ignore .cache file so we don't need
to look in sysfs for the complete list).
2016-04-01 14:49:39 +02:00
7ed5a65ee5 dev-cache: also add dev name for device found in sysfs only
For the case when we print device name associated with struct device
that was not found in /dev, but in sysfs, for example when printing
devices where LV device mismatch is found.
2016-04-01 14:48:56 +02:00
91d32f9d1b refactor: dev-cache: move code adding sysfs-only device into separate fn 2016-04-01 11:47:06 +02:00
0e774d5ae7 refactor: dev-cache: use btree instead of hash table for sysfs-only devices
major:minor btree is more convenient and more suitable than dev name
hash table here.
2016-04-01 11:42:25 +02:00
c577984630 tests: fixed cache target reacts faster
After kernel fixed in 4.6 cache target reacts promptly
and switches to Fail-ed state when disk error is detected.

Handle both cases in test...
2016-03-31 12:21:40 +02:00
bc5376b151 tests: do not test settings when MQ is emulated by SMQ 2016-03-31 12:21:40 +02:00
5034bb8d18 cleanup: use local var to read struct 2016-03-31 12:21:40 +02:00
b10253ab4d cleanup: use TARGET define 2016-03-31 12:21:40 +02:00
86db143307 cleanup: debug message fix
Reported-by: Ming-Hung Tsai <mingnus gmail com>
2016-03-31 12:21:25 +02:00
fc7dacaa4c thin: display highest mapped sector
Use  meta%  to expose highest mapped sector in thinLV.
so showing there 100.00% means thinLV maps latest sector.

Currently using a 'trick' with total_numerator to pass-in
device size when  'seg==NULL'

TODO: Improve device status API per target - current 'percentage'
is not really extensible.
2016-03-31 12:20:43 +02:00
8bbec41bd4 thin: no thin-pool flush when reading metadata status
Previous fix missed the fact the we do query for 'percent' with
seg value either set or unset (API overload...)
When 'seg' was unset, we still issue flush with status.
Fix it by cheking segtype by target_type.

As we check for segtype - we could also skip whole percentage
if the 'segtype' is unknown by code directly.

Reported-by: Ming-Hung Tsai <mingnus gmail com
2016-03-31 12:15:47 +02:00
fe7ae37f5e tests: vg-check-devs-used requires driver version 4.15 at least 2016-03-31 10:38:05 +02:00
9a086a6607 dev-cache: fix check for already indexed dev in _index_dev_by_vgid_and_lvid 2016-03-30 15:57:57 +02:00
06ef7ba876 doc: describe lvmlockd/lvmpolld features as available if LVM compiled with lockd/polld support 2016-03-30 14:10:56 +02:00
8b258a005b dev-cache: dev_cache_index_devs fn is available unconditionally
The new dev_cache_index_devs fn was under ifdef UDEV_SYNC_SUPPORT by mistake,
move it out of this ifdef.
2016-03-30 13:06:20 +02:00
52e0d0db44 dev-cache: remove spurious error msg if no value found in /sys/dev/block/<major>:<minor>/dm/uuid during dev scan
It's correct to have a DM device that has no DM UUID assigned
so no need to issue error message in this case. Also, if the
device doesn't have DM UUID, it's also clear it's not an LVM LV
(...when looking for VGID/LVID while creating VGID/LVID indices
in dev cache).

For example:

$ dmsetup create test --table "0 1 linear /dev/sda 0"
And there's no PV in the system.

Before this patch (spurious error message issued):
$ pvs
  _get_sysfs_value: /sys/dev/block/253:2/dm/uuid: no value

With this patch applied (no spurious error message):
$ pvs
2016-03-30 11:30:09 +02:00
8c27c52749 dev-cache: also index VGIDs and LVIDs if using persistent .cache file
If we're using persistent .cache file, we're reading this file instead
of traversing the /dev content. Fix missing indexing by VGID and LVID
here - hook this into persistent_filter_load where we populate device
cache from persistent .cache file instead of scanning /dev.

For example, inducing situation in which we warn about different device
actually used than what LVM thinks should be used based on metadata:

$ lsblk -s /dev/vg/lvol0
NAME     MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
vg-lvol0 253:4    0  124M  0 lvm
`-loop1    7:1    0  128M  0 loop

$ lvmconfig --type diff

global {
	use_lvmetad=0
}
devices {
	obtain_device_list_from_udev=0
}

(obtain_device_list_from_udev=0 also means the persistent .cache file is used)

Before this patch - pvs is fine as it does the dev scan, but lvs relies
on persistent .cache file and it misses the VGID/LVID indices to check
and warn about incorrect devices used:

$ pvs
  Found duplicate PV B9gXTHkIdEIiMVwcOoT2LX3Ywh4YIHgR: using /dev/loop0 not /dev/loop1
  Using duplicate PV /dev/loop0 without holders, ignoring /dev/loop1
  WARNING: Device mismatch detected for vg/lvol0 which is accessing /dev/loop1 instead of /dev/loop0.
  PV          VG Fmt  Attr PSize   PFree
  /dev/loop0 vg lvm2 a--  124.00m    0

$ lvs
  Found duplicate PV B9gXTHkIdEIiMVwcOoT2LX3Ywh4YIHgR: using /dev/loop0 not /dev/loop1
  Using duplicate PV /dev/loop0 without holders, ignoring /dev/loop1
  LV    VG Attr       LSize
  lvol0 vg -wi-a----- 124.00m

With this patch applied - both pvs and lvs is fine - the indices are
always created correctly (lvs just an example here, other LVM commands
that rely on persistent .cache file are fixed with this patch too):

$ pvs
  Found duplicate PV B9gXTHkIdEIiMVwcOoT2LX3Ywh4YIHgR: using /dev/loop0 not /dev/loop1
  Using duplicate PV /dev/loop0 without holders, ignoring /dev/loop1
  WARNING: Device mismatch detected for vg/lvol0 which is accessing /dev/loop1 instead of /dev/loop0.
  PV          VG Fmt  Attr PSize   PFree
  /dev/loop0 vg lvm2 a--  124.00m    0

$ lvs
  Found duplicate PV B9gXTHkIdEIiMVwcOoT2LX3Ywh4YIHgR: using /dev/loop0 not /dev/loop1
  Using duplicate PV /dev/loop0 without holders, ignoring /dev/loop1
  WARNING: Device mismatch detected for vg/lvol0 which is accessing /dev/loop1 instead of /dev/loop0.
  LV    VG Attr       LSize
  lvol0 vg -wi-a----- 124.00m
2016-03-30 11:00:01 +02:00
91bb202ded dev-cache: handle situation where device is referenced in sysfs, but the node is not yet in dev dir
It's possible that while a device is already referenced in sysfs, the node
is not yet in /dev directory.

This may happen in some rare cases right after LVs get created - we sync
with udev (or alternatively we create /dev content ourselves) while VG
lock is held. However, dev scan is done without VG lock so devices may
already be in sysfs, but /dev may not be updated yet if we call LVM command
right after LV creation (so the fact that fs_unlock is done within VG
lock is not usable here much). This is not a problem with devtmpfs as
there's at least kernel name for device in /dev as soon as the sysfs
item exists, but we still support environments without devtmpfs or
where different directory for dev nodes is used (e.g. our test suite).

This patch covers these situations by tracking such devices in
_cache.sysfs_only_names helper hash for the vgid/lvid check to work still.

This also resolves commit 6129d2e64d
which was then reverted by commit 109b7e2095
due to performance issues it may have brought (...and it didn't resolve
the problem fully anyway).
2016-03-30 10:56:46 +02:00
bc0372cf9d test: Add missing directory
Fix commit bb93a28bc1
2016-03-29 08:24:52 +02:00
d6e8f18e4d post-commit 2016-03-26 09:07:21 +00:00
b9d07f7a12 pre-release 2016-03-26 09:04:50 +00:00
a5d53aec83 libdm: Raid status region units are sectors 2016-03-24 17:42:36 +00:00
d243db5466 lvmdbusd: Add '-' to allowable PV device path chars 2016-03-24 12:27:02 -05:00
109b7e2095 revert: 6129d2e64d
Unfortunately, commit 6129d2e64d may
cause performance issue. There's going to be a better fix...
2016-03-24 14:06:12 +01:00
37b548c6b5 WHATS_NEW: commit 6129d2e64d 2016-03-24 12:47:35 +01:00
6129d2e64d monitoring: sync /dev content before contacting dmeventd for monitor/unmonitor
dmeventd daemon may call further code itself that looks at /dev, e.g.
via dmeventd_lvm2_command call. We need to have a consistent view of
the /dev content at that time. Therefore, sync /dev content before
calling monitoring hook which contacts dmeventd.

This problem was quite hidden before, but now it has manifested itself
because of recent additions to dev-cache code where we started looking
at device holders as seen in sysfs. What happened here was that the
device was already in sysfs, but not yet under /dev and this triggered
the new error message sometimes:

  log_error("%s: failed to find associated device structure for holder %s.", devname, devpath);

This problem has manifested recently in our api/pytest.sh test from
testsuite where we create thin pool LVs and thin LVs and hence it also
causes dmeventd to be used as well and these error messages were
visible there.
2016-03-24 12:40:19 +01:00
82d92009ae test: Move bus configuration to prepare function 2016-03-23 12:27:34 +01:00
1b0775916b test: Remove pidfile after killing the process
Though unlikely keeping files in place may result in random process
killed.
2016-03-23 12:25:18 +01:00
bb93a28bc1 test: Fix lvmdbusd tests to work with installed testsuite 2016-03-23 11:59:04 +01:00
c1d376b1ab test: Fix checks to skip lvmdbusd tests
The executable is always present in the tree, need to check the
runtime dependencies.
2016-03-23 11:58:48 +01:00
c6d383a6da properties: use proper 'get' variant for unimplemented _pv_major_get and _pv_minor_get fns 2016-03-23 10:52:46 +01:00
1056894f1f raid: Tidy dm_get_status_raid. [HM] 2016-03-22 21:39:52 +00:00
cf39346697 libdm: Move _skip_fields within file. 2016-03-22 19:35:14 +00:00
65d2d66d02 libdm: Change _advance_to_next_word to _skip_fields 2016-03-22 19:26:13 +00:00
1216efdf15 activate: Use macros for target and module names. 2016-03-22 17:46:15 +00:00
94f78e0183 coverity: fix some issues reported by coverity for recent code 2016-03-22 16:03:55 +01:00
3d26d283ea tests: update vg-check-devs-used.sh
Snapshot needs to be activated exclusively in cluster...
2016-03-22 11:18:22 +01:00
6a915270fc tests: update vg-check-devs-used.sh 2016-03-22 11:13:28 +01:00
ed002ed22a dev: also count with suffixes in UUID for LVs when constructing VGID and LVID index
UUID for LV is either "LVM-<vg_uuid><lv_uuid>" or "LVM-<vg_uuid><lv_uuid>-<suffix>".
The code before just checked the length of the UUID based on the first
template, not the variant with suffix - so LVs with this suffix were not
processed properly.

For example a thin pool LV (as an example of an LV that contains
sub LVs where UUIDs have suffixes):

[0] fedora/~ # lsblk -s /dev/vg/lvol1
NAME              MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
vg-lvol1          253:8    0    4M  0 lvm
`-vg-pool-tpool   253:6    0  116M  0 lvm
  |-vg-pool_tmeta 253:2    0    4M  0 lvm
  | `-sda           8:0    0  128M  0 disk
  `-vg-pool_tdata 253:3    0  116M  0 lvm
    `-sda           8:0    0  128M  0 disk

Before this patch (spurious warning message about device mismatch):

[0] fedora/~ # pvs
  WARNING: Device mismatch detected for vg/lvol1 which is accessing /dev/mapper/vg-pool-tpool instead of (null).
  PV         VG     Fmt  Attr PSize   PFree
  /dev/sda   vg     lvm2 a--  124.00m    0

With this patch applied (no spurious warning message about device mismatch):

[0] fedora/~ # pvs
  PV         VG     Fmt  Attr PSize   PFree
  /dev/sda   vg     lvm2 a--  124.00m    0
2016-03-22 10:52:24 +01:00
2a47f0957f dev: also check for blank sysfs value containing only '\n' 2016-03-22 09:29:24 +01:00
e69e81388d report: Add pv_major, pv_minor to reports. 2016-03-22 00:12:08 +00:00
16b1272597 lvmdbusd: Change print statements to log_error
Should not be using print() in the service code.

Signed-off-by: Tony Asleson <tasleson@redhat.com>
2016-03-21 17:28:51 -05:00
ca28ea88be lvmdbusd: Add lvm flight recorder
To help out with debug, when an exception is thrown in the dbus service we
will dump all the information we have on the last 16 commands that were
executed along with the stack strace.

Signed-off-by: Tony Asleson <tasleson@redhat.com>
2016-03-21 17:28:51 -05:00
a0c7875c54 lvmdbusd: Allow PV devices to be referenced by symlink(s)
See: https://bugzilla.redhat.com/show_bug.cgi?id=1318754

Signed-off-by: Tony Asleson <tasleson@redhat.com>
2016-03-21 17:28:51 -05:00
86e9d12b6f lvmdbusd: Remove --udev in service file
With commit 2d5dc6512e the dbus server
no longer needs to utilize udev to know when to update its internal
state.

Signed-off-by: Tony Asleson <tasleson@redhat.com>
2016-03-21 17:28:51 -05:00
cc57cd39ab tests: add vg-check-devs-used.sh 2016-03-21 16:21:30 +01:00
8fad9b9e5d dev: be safer when reading sysfs properties
Check if the value we read from sysfs is not blank and replace the '\n'
at the end only when needed ('\n' should usually be there for sysfs values,
but better check this).
2016-03-21 15:50:32 +01:00
ca7bac53cf test: Turn on dbus test
(cherry picked from commit f1ea96c6c1dc6414169bda1a18cf14cd9ebb1493)
2016-03-21 15:22:58 +01:00
f231bdb20b metadata: use own mem pool to report PV device mismatch in VG 2016-03-21 14:39:11 +01:00
03b0a78640 dev: detect mismatch between devices used and devices assumed for an LV
It's possible for an LVM LV to use a device during activation which
then differs from device which LVM assumes based on metadata later on.

For example, such device mismatch can occur if LVM doesn't have
complete view of devices during activation or if filters are
misbehaving or they're incorrectly set during activation.

This patch adds code that can detect this mismatch by creating
VG UUID and LV UUID index while scanning devices for device cache.

The VG UUID index maps VG UUID to a device list. Each device in the
list has a device layered above as a holder which is an LVM LV device
and for which we know the VG UUID (and similarly for LV UUID index).

We can acquire VG and LV UUID by reading /sys/block/<dm_dev_name>/dm/uuid.
So these indices represent the actual state of PV device use in
the system by LVs and then we compare that to what LVM assumes
based on metadata.

For example:

[0] fedora/~ # lsblk /dev/sdq /dev/sdr /dev/sds /dev/sdt
NAME         MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINT
sdq           65:0    0  104M  0 disk
|-vg-lvol0   253:2    0  200M  0 lvm
`-mpath_dev1 253:3    0  104M  0 mpath
sdr           65:16   0  104M  0 disk
`-mpath_dev1 253:3    0  104M  0 mpath
sds           65:32   0  104M  0 disk
|-vg-lvol0   253:2    0  200M  0 lvm
`-mpath_dev2 253:4    0  104M  0 mpath
sdt           65:48   0  104M  0 disk
`-mpath_dev2 253:4    0  104M  0 mpath

In this case the vg-lvol0 is mapped onto sdq and sds becauset this is
what was available and seen during activation. Then later on, sdr and
sdt appeared and mpath devices were created out of sdq+sdr (mpath_dev1)
and sds+sdt (mpath_dev2). Now, LVM assumes (correctly) that mpath_dev1
and mpath_dev2 are the PVs that should be used, not the mpath
components (sdq/sdr, sds/sdt).

[0] fedora/~ # pvs
  Found duplicate PV xSUix1GJ2SK82ACFuKzFLAQi8xMfFxnO: using /dev/mapper/mpath_dev1 not /dev/sdq
  Using duplicate PV /dev/mapper/mpath_dev1 from subsystem DM, replacing /dev/sdq
  Found duplicate PV MvHyMVabtSqr33AbkUrobq1LjP8oiTRm: using /dev/mapper/mpath_dev2 not /dev/sds
  Using duplicate PV /dev/mapper/mpath_dev2 from subsystem DM, ignoring /dev/sds
  WARNING: Device mismatch detected for vg/lvol0 which is accessing /dev/sdq, /dev/sds instead of /dev/mapper/mpath_dev1, /dev/mapper/mpath_dev2.
  PV                     VG     Fmt  Attr PSize   PFree
  /dev/mapper/mpath_dev1 vg     lvm2 a--  100.00m      0
  /dev/mapper/mpath_dev2 vg     lvm2 a--  100.00m      0
2016-03-21 11:40:40 +01:00
65d9f742f8 device: add DEV_OPEN_FAILURE flag
DEV_OPEN_FAILURE flag is set if the most recent "open" for a device
failed and it's unset if any subsequent "open" succeeds.
2016-03-21 11:06:05 +01:00
e58d24293f post-release 2016-03-19 01:18:28 +00:00
0d4b6bdfc0 pre-release 2016-03-19 01:14:29 +00:00
6c10d1f3d9 fsadm: use stat to get major:minor pair for non-standard /dev layouts
If we're using non-standard /dev layout so we can't get the dm-X name
easily, we can't also look at the /sys/blocl/dm-X/dev to get the major:minor
pair. Use "stat" in this case even though it triggers automounts
(but there's no better way for now).
2016-03-18 17:21:47 +01:00
2879eff86e fsadm: if available, use /proc/self/mountinfo to detect mounted volume
The /proc/self/mountinfo is not bound to device names like /proc/mounts
and it uses major:minor pairs instead.

This fixes a situation in which a volume is mounted and then renamed
later on - that makes /proc/mounts unreliable when detecting mounted
volumes.

See also https://bugzilla.redhat.com/show_bug.cgi?id=1196910.
2016-03-18 13:42:06 +01:00
464ebe04db tests: stacked resize of thin on raid 2016-03-15 23:22:52 +01:00
51ed48f855 lvresize: fix stacked resize
Commit b64703401d cause regression
when handling stacked resize of pool metadata volume that would
be a raid LV.

Fix it by properly setting up size also for layer extension.
2016-03-15 23:21:16 +01:00
746f8af2a8 tests: update lvconvert test 2016-03-14 23:46:08 +01:00
0d5b9deff2 tests: use own PID path for lvmetad checking
Do not try to check PID of running lvmetad and use own path.
2016-03-14 23:45:45 +01:00
7daba90fa3 lvconvert: fix error path test
lvremove_single toollib function returns
ECMD_FAILED or ECMD_PROCESSED.
2016-03-14 23:37:42 +01:00
a39563c0b0 report: Use default vg_name field width too. 2016-03-14 09:30:51 +00:00
a78e696070 post-release 2016-03-11 00:21:53 +00:00
2159a1429d pre-release 2016-03-11 00:19:16 +00:00
6807eb8863 man: vgcreate shared 2016-03-10 15:40:37 -06:00
0f10823ec9 pvchange, pvresize: move exported VG check
Allow pvchange and pvresize to process exported VGs,
and have them check for the exported state in their
single function.

Previously, the exported VG state would trigger a
failure in vg_read()/ignore_vg() because the VGs are
being read with READ_FOR_UPDATE.  Because these commands
read all VGs to search for the intended PVs, any
exported VG would trigger a failure, even if it was
not related to the intended PV.
2016-03-10 13:37:42 -06:00
9f4451193b lvconvert: update --help
Use  <>  around user entered option parameters to make it visually
different (just like we use Italic style in man page).

TODO:

In the future we should consistently provide such notation and
possibly generate it automagically from some internal data structures.

Preferably for man pages as well so we report actual set of supported
options.
2016-03-10 18:38:54 +01:00
5bfc0edd12 tests: uncache with missing PV
For now repair of cache with missing PVs via usage of --uncache.
More will follow later.
2016-03-10 18:38:54 +01:00
00e641ef37 cleanup: display_lvname 2016-03-10 18:38:54 +01:00
8507db1924 cleanup: reoder lines 2016-03-10 18:38:54 +01:00
b36cf94318 cleanup: add backtrace 2016-03-10 18:38:54 +01:00
8e9deb2e70 gcc: cast time_t to 64bit
Value is printed as uint64, so make sure right type is passed on all
platforms. Fixes gcc warning on some 32bit platforms.
2016-03-10 18:38:54 +01:00
5aade9c402 topology: handle reported sizes smaller then sector
Recent kernel (4.4) start to report values smaller then sector size
(but in reporting size for SSD which support data zeroing on discard).

For now log warning and assume it really means 1 sector.

Addressing RHBZ:
https://bugzilla.redhat.com/show_bug.cgi?id=1313377
2016-03-10 18:38:54 +01:00
a494d85ef6 man: drop extra braces
doclifter tool noticed wrong brackets.
2016-03-10 18:38:54 +01:00
386208e593 man: updates
Continuing with lvconvert style updates.

Minimize usage of '\:' as zero-width break space, since html renderers
do not handle this groff sign well (some of them seems to even render
':' there).
But since we do not want see badly rendered man pages itself, prefer
the 'man visual' appearence over html page generation (man2html should
be actually fixed).

Start to use 'user input option' with Capitals more consistently.
2016-03-10 18:38:54 +01:00
86a23b2145 makefiles: avoid using vpath for rules files
Fixing vpath usage as it has been checking for existance of
generated file also in the $(scrdir) e.g.:

No need to remake target '10-dm.rules.in'; using VPATH name '...'

If the $(srcdir) had been also $(builddir) and contained already
generated rules file, it's been used instead generating new
one.

(See: http://make.mad-scientist.net/papers/how-not-to-use-vpath/)
2016-03-10 18:38:53 +01:00
70cbd8f1a5 lvconvert: improve vg parameter parsing
Commit abd9618dd8 tried to improve
parsing of vg name from logical path - but still missed couple
corner cases.

This patch further improves the logic and reuses
validate_lvname_param() for parsing of lv_name.

Also explicitly checks for LVM_VG_NAME in the right case.

So now also properly parses cases like:
  'lvconvert --repairt vg/'
and will provide correct error message.
2016-03-10 18:38:53 +01:00
5c415afd85 cache: check for cache fail during flush
Just WARN if the cache can't be flushed because it's failed.
2016-03-10 18:38:53 +01:00
569ba79abf lvconvert: uncache handles missing PV
Allow to process with --uncache when some PVs are missing in VG.

So it's now possible to --uncache cached LV if the cache-pool
has missing PV.
2016-03-10 18:38:53 +01:00
29d1533a49 libdm: parse more info from cache status
Parse Fail/Error/need_check/ro status info from cache.
2016-03-10 18:38:53 +01:00
9918d95490 metadata: do not issue warning message about PV dev size being 0 when the device has gone just after VG read
There's a window between doing VG read and checking PV device size
against real device size. If the device is removed in this window,
the dev cache still holds struct device and pv->dev still references
that and that PV is not marked as missing. However, if we're trying
to get size for such device, the open fails because that device
doesn't exists anymore.

We called existing pv_dev_size in _check_pv_dev_sizes fn. But
pv_dev_size assigned a size of 0 if the dev_get_size it called failed
(because the device is gone).

So call the dev_get_size directly and check for the return code
in _check_pv_dev_sizes and go further only if we really know the
device size. This is to avoid confusing warning messages like:

  Device /dev/sdd1 has size of 0 sectors which is smaller than corresponding PV size of 31455207 sectors. Was device resized?
  One or more devices used as PVs in VG helter_skelter have changed sizes.
2016-03-10 13:11:15 +01:00
8f01ee3035 remove unused define 2016-03-09 13:38:04 -06:00
18291fd016 test: Remove work-in-progress code from dbustest
(cherry picked from commit 3189d4d50492f5b78cf3920a7f499fd1020983c6)
2016-03-09 14:04:28 +01:00
e72184bb76 spec: Fix gobject dependency
Use python3-gobject-base instead of python3-gobject requiring xorg

(cherry picked from commit d929d82116759f53484e662b967165ef4fe4257c)
2016-03-09 14:00:05 +01:00
55d1105fc9 test: skip unrelated tests while testing lvmpolld 2016-03-09 12:59:45 +01:00
5434e9f5ea test: fix inverted condition 2016-03-09 12:59:42 +01:00
e655ccb418 test: Add prepare_lvmdbusd
- Check for running lvmdbusd at start
- Add teardown for lvmdbusd
2016-03-09 10:58:21 +01:00
d7ca164597 spec: Add missing dependency for dbusd
(cherry picked from commit 7435de21492f6b37ac7664d1f27b4a8dcc4d0dd4)
2016-03-09 10:58:21 +01:00
cb968ee875 test: Comment out incorrect lockd setup 2016-03-09 10:58:21 +01:00
c6e1845f76 test: Move udev-lvmlockd-test to check_system 2016-03-09 10:58:21 +01:00
2cf13b701a test: Update kernels to skip thin-flags with
See ed5e5c38b5
2016-03-09 10:09:29 +01:00
6d19c14c28 lvmdbus: Fix deprecated warnings for GObject use
While running on F24 a number of warnings were being emitted from using the
deprecated GObject instead of GLib.  Tested on python 3.4 and 3.5.

Signed-off-by: Tony Asleson <tasleson@redhat.com>
2016-03-08 16:07:35 -06:00
3f5629302a lvmdbus: Fix exception during exception handling
Python 3.5 in F24 was throwing the following exception:

Traceback (most recent call last):
  File "/usr/lib/python3.5/site-packages/lvmdbusd/main.py", line 73, in process_request
    req.run_cmd()
  File "/usr/lib/python3.5/site-packages/lvmdbusd/request.py", line 73, in run_cmd
    self.register_error(-1, st)
  File "/usr/lib/python3.5/site-packages/lvmdbusd/request.py", line 123, in register_error
    self._reg_ending(None, error_rc, error)
  File "/usr/lib/python3.5/site-packages/lvmdbusd/request.py", line 115, in _reg_ending
    self.cb_error(self._rc_error)
  File "/usr/lib64/python3.5/site-packages/dbus/service.py", line 669, in <lambda>
    keywords[error_callback] = lambda exception: _method_reply_error(connection, message, exception)
  File "/usr/lib64/python3.5/site-packages/dbus/service.py", line 293, in _method_reply_error
    exception))
  File "/usr/lib64/python3.5/traceback.py", line 136, in format_exception_only
    return list(TracebackException(etype, value, None).format_exception_only())
  File "/usr/lib64/python3.5/traceback.py", line 442, in __init__
    if (exc_value and exc_value.__cause__ is not None
AttributeError: 'str' object has no attribute '__cause__'

This was caused because we were calling the dbus error callback with a
string instead of an actual exception.  On python 3.4 this was apparently
OK, but not with 3.5.  Corrected to pass the exception to error callback.
Change tested on both python 3.4 and 3.5.

Reported-by: Vratislav Podzimek <vpodzime@redhat.com>
Signed-off-by: Tony Asleson <tasleson@redhat.com>
2016-03-08 16:06:45 -06:00
90c5d470c2 report: Tidy some field names, widths and headings.
Specifying an output width of 0 now leads to a default minimum width
taken from the width of the column heading.  (Most fields should use
this.)

Components of field names are generally separated by underscores (which
are optional at run-time).  (Dropped 3 duplicate fields now covered by
this rule.)

Each field heading must be unique and generally doesn't have spaces
between words (which get capitalised) unless they are already short and
the fields are normally longer or clarity demands it.
2016-03-08 19:50:22 +00:00
6cf1eff46d toollib: always process in use pvs
With the recent conversion of pvcreate/pvremove to the
common toollib processing function, skipping in-use PVs
in _process_pvs_in_vg prevented them from being protected
as intended by the in-use flag.

The processing code for pvcreate/pvremove checks for the
in-use state itself and prevents using an in-use PV.
If a PV is skipped, it looks like an unused device and
is not protected from being used in pvcreate/pvremove.
2016-03-07 14:15:33 -06:00
a8319e62c0 vgscan: add --notifydbus to send a notification
This command option can be used to trigger a D-Bus
notification independent of the usual notifications
that are sent from other commands as an effect of
changes to PV/VG/LV state.  If lvm is not built with
dbus notification support or if notify_dbus is disabled
in the config, this command will exit with an error.
2016-03-07 10:50:45 -06:00
2d5dc6512e dbus: add notification from commands
When a command modifies a PV or VG, or changes the
activation state of an LV, it will send a dbus
notification when the command is finished.  This
can be enabled/disabled with a config setting.
2016-03-07 10:06:09 -06:00
18cf5e8e67 raid_manip: allow for raid leg to be replaced when not both data and metadata image are on pvs
resolves rhbz#1130329
2016-03-07 15:25:30 +01:00
d03b1779b4 coverity: fix possible resource leak in _print_historical_lv function
The code in _print_historical_lv function works with temporary
"descendants_buffer" that is allocated and freed within this
function.

When printing text out, we used "outf" macro which called
"out_text" fn and it checked return value and if failed,
the macro called "return_0" automatically. But since we
use the temporary buffer, if any of the out_text calls
fails, we need to deallocate this buffer properly - that's
the "goto_out", otherwise we'll be leaking memory.

So add new "outfgo" helper macro which does the same as "outf",
but it calls "goto_out" instead of "return_0" so we can jump
to a cleanup hook at the end.
2016-03-07 10:43:50 +01:00
7b15ca5c9a post-release 2016-03-04 18:06:24 +00:00
68ec240b99 pre-release 2016-03-04 17:59:21 +00:00
6c78175126 lvmdbusd: Set locale
Signed-off-by: Tony Asleson <tasleson@redhat.com>
2016-03-04 10:13:04 -06:00
f94fe2c91f dbustest.sh: Get dbus test to work on buildbot
- stdout/stderr for test output
- debug.log* for daemon output
- use install instead of cp for DBus config
- use system bus
- DBus reloads on new file. Better having it created with correct
  permissions.

Notes:
- Squashed commits from mcsontos development branch
- Still disabled at this time

Signed-off-by: Tony Asleson <tasleson@redhat.com>
2016-03-04 10:11:03 -06:00
9720898c8e libdm: config: fix dm_config_write_node and variants to properly return error on failures
The error was not propagated if _write_config (that is part of
dm_config_write_node and all its variants) was called recursively
for subsections.
2016-03-04 15:51:13 +01:00
67c5006e12 cleanup: previous patch with libdm config node buffer size 2016-03-04 15:19:09 +01:00
967a0889a0 libdm: config: remove 4096 char limit due to buffer size if writing dm_config_node 2016-03-04 14:59:22 +01:00
418b7c6be8 WHATS_NEW: historical LVs 2016-03-04 12:08:02 +01:00
e447ab87e9 man: lvrename: also mention possibility to rename historical logical volumes 2016-03-04 11:51:57 +01:00
fa06c2263b cleanup: comment in the code for renaming historical LVs 2016-03-04 11:46:29 +01:00
27245d97e5 lvrename: support renaming historical logical volumes 2016-03-04 11:36:24 +01:00
b114b4d723 commands: lvdisplay: recognize -H|--history switch 2016-03-04 10:27:45 +01:00
ad9cbe2714 tests: direct control of lvm1 usage in tests
Using lvm1 metadata with lvmetad is not generally allowed,
but nothing has prevented creating new lvm1 metadata with
lvmetad (missing error checking in pvcreate/vgcreate.)
Various tests are using lvm1 with lvmetad and happen to
work because of the missing error checks.

This commit fixes the tests so they won't fail when the
lvm1/lvmetad error checking is fixed.  A new variable
LVM_TEST_LVM1 is defined and is used in the scripts to
decide if lvm1 metadata should be tested.  LVM_TEST_LVM1
is not defined when lvmetad is being tested, and the
combination of LVM_TEST_LVM1 and LVM_TEST_LVMETAD can
be used to verify the desired lvmetad+lvm1 behavior.
2016-03-03 14:43:19 -06:00
5764c484ea man: Add some information about historical LVs. 2016-03-03 17:09:25 +00:00
9a78c258ba tests: add lv-ancestry.sh test 2016-03-03 13:50:59 +01:00
45c82260db tests: add "get lvh_field" for "lvs -H" 2016-03-03 13:50:59 +01:00
b39473a537 lvmdump: also list historical LVs in lvmdump 2016-03-03 13:50:59 +01:00
8a601454e1 metadata: automatically remove invalid (dangling) historical LVs
Historical LV is valid as long as there is at least one live LV among
its ancestors. If we find any invalid (dangling) historical LVs, remove
them automatically.
2016-03-03 13:50:59 +01:00
1297b0c8be metadata: also validate historical LVs in VG in vg_validate and check_lv_segments 2016-03-03 13:50:59 +01:00
fc628e92ba metadata: also look at historical LVs when checking LV name availability
Live LVs and historical LVs are in one namespace and the name needs to
be unique in whole VG.
2016-03-03 13:50:59 +01:00
0ab1110164 conf: regenerate example.conf.in 2016-03-03 13:50:59 +01:00
ff6e124a33 conf: add metadata/lvs_history_timeout configuration setting 2016-03-03 13:50:59 +01:00
74272e163d metadata: add vg_strip_outdated_historical_lvs fn and call it during VG read
The vg_strip_outdated_historical_lvs iterates over the list of historical LVs
we have and it shoots down the ones which are outdated.

Configuration hook to set the timeout will be in subsequent patch.
2016-03-03 13:50:59 +01:00
53b064b9ae commands: lvremove: also process historical LVs 2016-03-03 13:50:59 +01:00
f833a6d074 metadata: add historical_glv_remove 2016-03-03 13:50:57 +01:00
ccebf3100d conf: add metadata/record_lvs_history configuration setting
The metadata/record_lvs_history is global switch which enables or
disables recording historical LVs in metadata.

If both metadata/record_lvs_history=1 lvm.conf option and
--nohistory command switch is used at the same time, the
--nohistory prevails.
2016-03-03 13:49:15 +01:00
b1399090cd commands: lvremove: recognize --nohistory option 2016-03-03 13:49:15 +01:00
f545dd5952 metadata: honour 'nohistory' switch when removing thin LVs
When --nohistory switch is used with lvremove, the LV that is removed is
not recorded in metadata as 'historical LV'.
2016-03-03 13:49:15 +01:00
9a34de9cb9 cmd: add 'nohistory' option and wire it up in cmd_context
The --nohistory switch will cause historical LVs to not be recorded
in metadata on demand.
2016-03-03 13:49:15 +01:00
8f47119f6f report: add new 'none' lv_layout and 'history' lv_role and mark historical LVs that way
Report proper values for historical LVs in lv_layout and lv_role fields.
Any historical LV doesn't have any layout anymore and the role is "history".

For example:

$ lvs -H -o name,lv_attr,lv_layout,lv_role vg/-lvol1
  LV     Attr       Layout     Role
  -lvol1 ----h----- none       public,history
2016-03-03 13:49:15 +01:00
0339a5f447 report: add full_descendants field to display descendants with history
Same as lv_full_ancestors, but the other way round in the ancestry chain.
2016-03-03 13:49:15 +01:00
715f1fb4c4 report: add full_ancestors field to display ancestors with history
The lv_full_ancestors reporting field is just like the existing
lv_ancestors field but it also takes into account any history and
indirect relations recorded.
2016-03-03 13:49:15 +01:00
f228750386 report: report historical LV names with '-' prefix
All names for historical LVs are prefixed with '-' character to make clear
difference between live and historical LVs. The '-' can't be set by users
for live LV names during lvcreate hence we never get into a conflict with
the names that user defines for live LVs.
2016-03-03 13:49:15 +01:00
8b9953e8c5 report: display (h)istorical state in lv_attr field
The 'historical' state is displayed as 5th bit ("state") in the lv_attr
field and denoted by new 'h' character.
2016-03-03 13:49:15 +01:00
2af5971523 report: add lv_historical field to identify historical LVs
The lv_historical reporting field is a simple binary field that reports
whether an LV is historical one ("historical" value or value of "1" displayed)
or not (blank string "" or value of "0" displayed).
2016-03-03 13:49:15 +01:00
e112f5ce05 commands: lvs: recognize -H|--history switch
When lvs command is used together with the -H|--history switch,
all historical LVs are reported as well.
2016-03-03 13:49:14 +01:00
28f96d5ab6 report: display lv_name,lv_uuid,vg_name,lv_time and new lv_time_removed for historical LVs 2016-03-03 13:49:14 +01:00
2e7a121062 toollib: honour '-H|--history' switch while executing process_each_lv_in_vg
When processing LVs in a VG and when the -H|--history switch is used,
make process_each_lv_in_vg to iterate over historical volumes too.

For each historical LV, we use dummy struct logical_volume instance with
the "this_glv" reference set to a wrapper over proper struct
historical_logical_volume representation. This makes it possible to process
historical LVs just like normal live LVs (though a dummy one without any
segments and all the other fields zeroed and blank) and it also allows
for using all historical LV related information via lv->this_glv->historical
reference.

One can use a simple call to lv_is_historical to make a difference between
live and historical LV in all the code that is called by process_each_* fns.
2016-03-03 13:49:14 +01:00
f7e0a4cc18 cmd: add '-H|--history' switch and wire it up in cmd_context and processing_handle
This patch adds "include_historical_lvs" field to struct cmd_context to
make it possible for the command to switch between original funcionality
where no historical LVs are processed and functionality where historical
LVs are taken into account (and reported or processed further). The switch
between these modes is done using the '-H|--history' switch on command
line.

The include_historical_lvs state is then passed to process_each_* fns
using the "include_historical_lvs" field within struct processing_handle.
2016-03-03 13:49:14 +01:00
baee45a103 metadata: add lv_is_historical fn to test if the LV is historical one 2016-03-03 13:49:14 +01:00
673bc0636c metadata: format_text: interconnect historical LVs among each other and also with live LVs
Interconnect historical LVs in an ancestry chain and also connect the first/last
one with its live ancestor/descendant if it exists.
2016-03-03 13:49:13 +01:00
a61bc70f62 metadata: add support for interconnection of thin pool LV segment with indirect origin
Add support for making an interconnection between thin LV segment and
its indirect origin (which may be historical or live LV) - add a new
"indirect_origin" argument to attach_pool_lv function.
2016-03-03 13:46:40 +01:00
c45af2df4e metadata: add find_historical_glv fn
The find_historical_glv is helper function that looks up historical
LV in struct volume_group's historical_lvs list and returns it if
found.
2016-03-03 13:46:39 +01:00
a0842d1f25 metadata: format_text: import historical LVs
Import historical LV list from metadata and add it to struct
volume_group's historical_lvs list.
2016-03-03 13:46:39 +01:00
54d3d976c7 metadata: format_text: reuse _print_timestamp fn 2016-03-03 13:46:39 +01:00
3a0ef77305 metadata: format_text: also export historical LVs
Also export historical LVs when exporting LVM2 metadata.
This is list of all historical LVs listed in
"historical_logical_volumes" metadata section with all
the properties exported for each historical LV.

For example, we have this thin snapshot sequence:

  lvol1 --> lvol2 --> lvol3
                 \
                  --> lvol4

We end up with these metadata:

logical_volume {
  ...
  (lvol1, lvol3 and lvol4 listed here as usual - no change here)
  ...
}

historical_logical_volumes {
  lvol2 {
    id = "S0Dw1U-v5sF-LwAb-W9SI-pNOF-Madd-5dxSv5"
    creation_time = 1456919613      # 2016-03-02 12:53:33 +0100
    removal_time = 1456919620       # 2016-03-02 12:53:40 +0100
    origin = "lvol1"
    descendants = ["lvol3", "lvol4"]
  }
}

By removing lvol1 further, we end up with:

historical_logical_volumes {
  lvol2 {
    id = "S0Dw1U-v5sF-LwAb-W9SI-pNOF-Madd-5dxSv5"
    creation_time = 1456919613      # 2016-03-02 12:53:33 +0100
    removal_time = 1456919620       # 2016-03-02 12:53:40 +0100
    origin = "-lvol1"
    descendants = ["lvol3", "lvol4"]
  }

  lvol1 {
    id = "me0mes-aYnK-nRfT-vNlV-UiR1-GP7r-ojbROr"
    creation_time = 1456919608      # 2016-03-02 12:53:28 +0100
    removal_time = 1456919767       # 2016-03-02 12:56:07 +0100
  }
}
2016-03-03 13:46:18 +01:00
790b2e8748 metadata: create historical LVs when LVs are removed and interconnect with live LVs
When an LV is being removed, we create an instance of
"struct historical_logical_volume" wrapped up in
"struct generic_logical_volume".

All instances of "struct historical_logical_volume" are then recorded in
"historical_lvs" list which is part of "struct volume_group".

The "historical LV" is then interconnected with "live LVs" to
connect a history chain for the live LV.
2016-03-03 11:26:51 +01:00
eeaa5a4481 metadata: add add_glv_to_indirect_glvs and remove_glv_from_indirect_glvs
The add_glv_to_indirect_glvs is a helper function that registers a
volume represented by struct generic_logical_volume instance ("glv")
as an indirect user of another volume ("origin_glv") and vice versa -
it also registers the other volume ("origin_glv") as indirect_origin
of user volume ("glv").

The remove_glv_from_indirect_glvs does the opposite.
2016-03-03 11:26:51 +01:00
937f72b168 metadata: add get_or_create_glv and get_or_create_glvl
The get_or_create_glv is helper function that retrieves any existing
generic_logical_volume wrapper for the LV. If the wrapper does not exist
yet, it's created.

The get_org_create_glvl is the same as get_or_create_glv but it creates
the glv_list wrapper in addition so it can be added to a list.
2016-03-03 11:26:51 +01:00
e573eca554 metadata: add infrastructure to track LV history
Add new structures and new fields in existing structures to support
tracking history of LVs (the LVs which don't exist - the have been
removed already):

  - new "struct historical_logical_volume"
    This structure keeps information specific to historical LVs
    (historical LV is very reduced form of struct logical_volume +
     it contains a few specific fields to track historical LV
     properties like removal time and connections among other LVs).

  - new "struct generic_logical_volume"
    Wrapper for "struct historical_logical_volume" and
    "struct logical_volume" to make it possible to handle volumes
    in uniform way, no matter if it's live or historical one.

  - new "struct glv_list"
    Wrapper for "struct generic_logical_volume" so it can be
    added to a list.

  - new "indirect_glvs" field in "struct logical_volume"
    List that stores references to all indirect users of this LV - this
    interconnects live LV with historical descendant LVs or even live
    descendant LVs.

  - new "indirect_origin" field in "struct lv_segment"
    Reference to indirect origin of this segment - this interconnects
    live LV (segment) with historical ancestor.

  - new "this_glv" field in "struct logical_volume"
    This references an existing generic_logical_volume wrapper for this
    LV, if used. It can be NULL if not needed - which means we're not
    handling historical LVs at all.

  - new "historical_lvs" field in "struct volume group
    List of all historical LVs read from VG metadata.
2016-03-03 11:26:51 +01:00
5e718ec666 tests: drop check for md5sum 2016-03-03 10:17:03 +01:00
49839b6d96 tests: check kernel_cache_ funcs 2016-03-03 10:17:03 +01:00
e04a0184cb cleanup: use lv_is_partial
Check for PARTIAL_LV flag in standard way.
2016-03-03 10:17:03 +01:00
a975dc530e cleanup: use _field_string
Make at least some 'advantage' in use local func and do dereference
internally from char pointer and use short list of params.
2016-03-03 10:17:03 +01:00
25bf0beedb man: minor updates
Minor fixes in few pages.
2016-03-03 10:17:03 +01:00
fd349cb2e5 man: lvconvert updates
Improving style (following lvcreate way).
Sorting options alphabetically.
2016-03-03 10:17:03 +01:00
88ce15004e cache: add kernel_cache_policy option
Pair kernel_cache_settings with kernel_cache_policy.
There is very small chance in error case that the value in table
might be differnet from the value stored in metadata
so make it 'checkable'.
2016-03-03 10:14:23 +01:00
3d610fabbd WHATS_NEW: [unknown] replaces 'unknown device' 2016-03-01 11:16:35 -06:00
57cd94b9e3 pvs: replace 'unknown device' with [unknown]
A config setting can restore the old string.
2016-03-01 11:12:03 -06:00
afae3355f8 cleanup: missplaced .
Remove misplaced '.' after '?'
Drop extra   'stack;'  after log_debug().
2016-03-01 17:20:47 +01:00
058eb3739d makefile: handle dm-version-expected 2016-03-01 16:03:02 +01:00
3b93c11030 man: fix mising braces
Fixing some reported issued found by:
http://catb.org/~esr/doclifter/bugs.html

Reported-by: Eric S. Raymond <esr at thyrsus.com>
2016-03-01 14:02:43 +01:00
872d5922e1 cleanup: indent and dots 2016-03-01 14:02:43 +01:00
36d0dcef38 coverity: eliminate DEADCODE
Coverity notice this cannot be NULL: cur = &dms->regions[*cur_r]
so avoid NULL checking and simplify form.
2016-03-01 14:02:43 +01:00
8173c2ff9a coverity: missing error path 2016-03-01 14:02:43 +01:00
b2d819eafa update WHATS_NEW
including changes not recorded for the previous release.
2016-02-29 13:50:02 -06:00
e3b904fd08 tests: check [unknown] in lvmetad-pvscan-cache
Update test for new [unknown] VG name from
commit 250b9153.
2016-02-29 12:43:07 -06:00
250b915364 pvs: display VG name [unknown] for used PV without metadata
Rather than displaying a blank field for VG name.
2016-02-29 11:17:55 -06:00
4013e21ba8 post-release 2016-02-26 21:14:12 +00:00
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
834 changed files with 35644 additions and 10257 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.158(2)-git (2016-06-25)

View File

@ -1 +1 @@
1.02.111-git (2015-10-30)
1.02.128-git (2016-06-25)

306
WHATS_NEW
View File

@ -1,5 +1,309 @@
Version 2.02.134 -
Version 2.02.158 - 25th June 2016
=================================
Pool metadata lvresize uses now same code as resize of normal volume.
Preserve monitoring status when updating thin-pool metadata.
Return 0 (inactive) when status cannot be queried in _lv_active().
Switch to log_warn() for failing activation status query.
Replace vgimportclone script with binary.
While lvmetad is shutting down, continue handling all connections cleanly.
Refactor lvconvert argument handling code.
Notify lvmetad when vgcfgrestore changes VG metadata.
Add --logonly option to report only cmd log for a command, not other reports.
Add log/command_log_selection to configure default selection used on cmd log.
Use 'orphan' object type in cmd log for groups to collect PVs not yet in VGs.
Add lvm lastlog command for query and display of last cmd's log in lvm shell.
Report per-object return codes via cmd log while processing multiple objects.
Annotate processing code with log report hooks for per-object command log.
Also pass common printed messages (besides warnings and errors) to log report.
Log warnings and errors via report during cmd processing if this is enabled.
Make it possible to iterate over internal 'orphan' VGs in process_each_vg fn.
Make -S|--select option groupable that allows this option to be repeated.
Make -O|--sort option groupable that allows this option to be repeated.
Add --configreport option to select report for which next options are applied.
Add support for priorities on grouping command arguments.
Add report/{pvs,vgs,lvs,pvsegs,segs}_{cols,sort}_full to lvm.conf.
Add lvm fullreport command for joined PV, VG, LV and segment report per VG.
Integrate report group handling and cmd log report into cmd processing code.
Add log/report_command_log to lvm.conf to enable or disable cmd log report.
Add log/report_output_format to lvm.conf for default report output format.
Recognize --reportformat {basic|json} option to select report output format.
Add log/command_log_{sort,cols} to lvm.conf to configure command log report.
Add log_object_{type,name,id,group,group_id} fields to cmd log.
Add log_{seq_num,type,context,message,errno,ret_code} fields to cmd log.
Add CMDLOG report type - a separate report type for command logging.
Version 2.02.157 - 17th June 2016
=================================
Change pvscan --cache -aay to scan locally if lvmetad fails.
Version 2.02.156 - 11th June 2016
=================================
Don't allow duplicate orphan PVs to be used with vgcreate/vgextend/pvcreate.
Improve handling of lvmetad update failures.
Yes/No prompt accepts '^[ ^t]*([Yy]([Ee]([Ss]|)|)|[Nn]([Oo]|))[ ^t]*$'.
If available, also collect output from lsblk command when running lvmdump -s.
Version 2.02.155 - 3rd June 2016
================================
Reject PV tags on pvmove cmdline because only 1 PV is supported. (2.02.141)
Fix compilation error when building with configure --disable-devmapper.
Fix lvmconfig --type diff to display complete diff if config cascade used.
Automatically filter out partitioned loop devices with partscan (losetup -P).
Fix lvm devtypes internal error if -S used with field name from pvs/vgs/lvs.
When reporting Data%,Snap%,Meta%,Cpy%Sync use single ioctl per LV.
Add lvseg_percent_with_info_and_seg_status() for percent retrieval.
Enhance internal seg_status handling to understand snapshots better.
When refresh failed in suspend, call resume upon error path.
Support passthrough cache mode when waiting for clean cache.
Check cache status only for 'in-use' cache pools.
Extend setup_task() to preset flushing for dm_task object.
When checking LV is a merging COW, validate its a COW LV first.
Correcting value in copy_percent() for 100%.
Update vgreduce to use process_each_vg.
Update lvconvert to use process_each_lv.
Update pvscan to use process_each_vg for autoactivation.
Add basic support for --type raid0 using md.
Add support for lvchange --cachemode for cached LV.
Fix liblvm2app error handling when setting up context.
Delay liblvm2app init in python code until it is needed.
Simplify thread locking in lvmetad to fix locking problems.
Allow pvremove -ff to remove a duplicate PV.
Fix lvm2-activation-generator to read lvm.conf without full command setup.
Allow a minimal context to be used in lvm2app for reading lvm.conf.
Version 2.02.154 - 14th May 2016
================================
Fix liblvm segfault after failure initialising lvmetad connection.
Retry open without O_NOATIME if it fails (not file owner/CAP_FOWNER).
Split _report into one fn for options and arguments and one for processing.
Version 2.02.153 - 7th May 2016
===============================
Change warning messages related to duplicate PVs.
A named device is always processed itself, not switched for a duplicate.
Add PV attr "d" and report field "duplicate" for duplicate PVs.
Add config setting to disallow VG changes when duplicate PVs exist.
Use device size and active LVs to choose the preferred duplicate PV.
Disable lvmetad when duplicate PVs are seen.
Support --chunksize option also when caching LV when possible.
Add function to check for target presence and version via 1 ioctl.
Version 2.02.152 - 30th April 2016
==================================
Use any inherited tags when wiping metadata sub LVs to ensure activation.
Add str_list_wipe.
Improve support for interrupting procesing of volumes during lvchange.
Use failed command return code when lvchanging read-only volume.
Show creation transaction_id and zeroing state of pool with thin volume.
Stop checking for dm_cache_mq policy with cache target 1.9 (alias to smq).
Check first /sys/module/dm_* dir existance before using modprobe.
Remove mpath from 10-dm.rules, superseded by 11-dm-mpath.rules (mpath>=0.6.0).
Version 2.02.151 - 23rd April 2016
==================================
Fix error path after reusing of _setup_task (2.02.150).
Fix memory access for empty sysfs values (2.02.149).
Disable lvmetad when lvm1 metadata is seen, so commands revert to scanning.
Suppress errors when snapshot merge gets delayed because volume is in use.
Avoid internal snapshot LV names in messages.
Autodetect and use /run/lock dir when available instead of /var/lock.
lvchange --refresh for merging thin origin will retry to deactivate snapshot.
Recognize in-progress snapshot merge for thin volumes from dm table.
Avoid deciding to initiate a pending snapshot merge during resume.
Improve retrying lvmetad requests while lvmetad is being updated.
Read devices instead of using the lvmetad cache if rescan fails.
Move lvmetad token/filter check and device rescan to the start of commands.
Don't try deactivating fictional internal LV before snapshot merge. (2.02.105)
When not obtaining devs from udev, check they exist before caching them.
Detect device mismatch also when compiling without udev support.
Version 2.02.150 - 9th April 2016
=================================
Avoid using flushing dm status ioctl when checking for usable DM device.
Check for devices without LVM- uuid prefix only with kernels < 3.X.
Reuse %FREE size aproximation with lvcreate -l%PVS thin-pool.
Allow the lvmdump directory to exist already provided it is empty.
Show lvconverted percentage with 2 decimal digits.
Fix regression in suspend when repairing --type mirror (2.02.133).
Version 2.02.149 - 1st April 2016
=================================
Do not flush thin-pool when checking metadata fullness.
Remove spurious error about no value in /sys/dev/block/major:minor/dm/uuid.
Fix device mismatch detection for LV if persistent .cache file is used.
Fix holder device not being found in /dev while sysfs has it during dev scan.
Version 2.02.148 - 26th March 2016
==================================
Introduce TARGET_NAME and MODULE NAME macros.
Replace hard-coded module and target names with macros.
Add pv_major and pv_minor report fields.
Detect and warn about mismatch between devices used and assumed for an LV.
Version 2.02.147 - 19th March 2016
==================================
If available, use /proc/self/mountinfo to detect mounted volume in fsadm.
Fix resize of stacked raid thin data volume (2.02.141).
Fix test for lvremove failure in lvconvert --uncache (2.02.146).
Version 2.02.146 - 11th March 2016
==================================
More man page cleanups in lvconvert.
Fix makefile vpath in /udev when generating udev rules files.
Another attempt to improve VG name parsing for lvconvert (2.02.144).
Use new cache status info and skip flushing for failed cache.
Support --uncache with missing PVs.
Tidy report field names, headings and widths.
Add vgscan --notifydbus to send a dbus notification.
Add dbus notification from commands after a PV/VG/LV changes state.
Version 2.02.145 - 4th March 2016
=================================
Make it possible to use lvremove and lvrename on historical LVs.
For historical LVs, report 'none' for lv_layout and 'history' for lv_role.
Add full_{ancestors,descendants} fields to report LV ancestry with history.
Report (h)istorical state within 5th bit (State) of the lv_attr field.
Add lv_historical reporting field to report if LV is historical or not.
Add lv_time_removed reporting field to display removal time for hist. LVs.
Report lv_name, lv_uuid, vg_name, lv_time for historical LVs.
Add --nohistory switch to lvremove to disable history recording on demand.
Add -H|--history switch to lvs and lvdisplay to include historical LVs.
Create historical LVs out of removed thin snapshot LVs and record in history.
Add metadata/lvs_history_retention_time for automatic removal of hist. LVs.
Add metadata/record_lvs_history config for switching LV history recording.
Add support and infrastructure for tracking historical LVs.
Improve lvconvert man page.
Add kernel_cache_policy lvs field.
Display [unknown] instead of 'unknown device' in pvs output.
Fix error path when pvcreate allocation fails (2.02.144).
Display [unknown] instead of blank for unknown VG names in pvs output.
Version 2.02.144 - 26th February 2016
=====================================
Use new PV processing code in pvcreate/vgcreate/vgextend/pvremove.
Add new PV processing code that prompts user without locks held.
Prevent lvmlockd blocking with new flag requiring sanlock 3.3.0.
Only show (u)sed pv_attr char when PV is not (a)llocatable. (2.02.143)
Update makefile to generate lcov output also for lvmpolld and lvmlockd.
Fix SystemdService lvm2-lvmdbusd.service name.
Improve support for env LVM_VG_NAME for reference VG name in lvconvert.
Fix regression when lvresize accepted zero sizes. (2.02.141)
Always warn user about PV in use even when pvremove uses --force --force.
Use uninitialized pool header detection in all cases.
Fix read error detection when checking for uninitialized thin-pool header.
Fix error path for internal error in lvmetad VG lookup code.
Version 2.02.143 - 21st February 2016
=====================================
Fix error path when sending thin-pool message fails in update_pool_lv().
Support reporting CheckNeeded and Fail state for thin-pool and thin LV.
For failing thin-pool and thin volume correctly report percentage as INVALID.
Report -1, not 'unkown' for lv_{snapshot_invalid,merge_failed} with --binary.
Add configure --enable-dbus-service for an LVM D-Bus service.
Replace configure --enable-python_bindings with python2 and python3 versions.
If PV belongs to some VG and metadata missing, skip it if system ID is used.
Automatically change PV header extension to latest version if writing PV/VG.
Identify used PVs in pv_attr field by new 'u' character.
Add pv_in_use reporting field to report if PV is used or not.
Add pv_ext_vsn reporting field to report PV header extension version.
Add protective flag marking PVs as used even if no metadata available.
Version 2.02.142 - 15th February 2016
=====================================
Fix memory pool corruption in pvmove (2.02.141).
Support control of spare metadata creation when repairing thin-pool.
Fix config type of 'log/verbose' from bool to int (2.02.99).
Fix inverted data LV thinp watermark calc for dmeventd response (2.02.133).
Use use_blkid_wiping=0 if not defined in lvm.conf and support not compiled in.
Do not check for suspended devices if scanning for lvmetad update.
Clear cached bootloader areas when PV format changed.
Fix partn table filter with external_device_info_source="udev" and blkid<2.20.
Version 2.02.141 - 25th January 2016
====================================
Add metadata/check_pv_device_sizes switch to lvm.conf for device size checks.
Warn if device size is less than corresponding PV size in metadata.
Cache device sizes internally.
Restore support for command breaking in process_each_lv_in_vg() (2.02.118).
Use correct mempool when process_each_lv_in_vg() (2.02.118).
Fix lvm.8 man to show again prohibited suffixes.
Fix configure to set proper use_blkid_wiping if autodetected as disabled.
Initialise udev in clvmd for use in device scanning. (2.02.116)
Add seg_le_ranges report field for common format when displaying seg devices.
Honour report/list_item_separator for seg_metadata_le_ranges report field.
Don't mark hidden devs in -o devices,metadata_devices,seg_pe_ranges.(2.02.140)
Change LV sizes in seg_pe_ranges report field to match underlying devices.
Add kernel_cache_settings report field for cache LV settings used in kernel.
Version 2.02.140 - 16th January 2016
====================================
Fix lvm2app to return either 0 or 1 for lvm_vg_is_{clustered,exported}.
Add kernel_discards report field to display thin pool discard used in kernel.
Correct checking of target presence when driver access is disabled.
Eval poolmetadatasize arg earlier in lvresize.
Fix vgcfgrestore to respect allocatable attribute of PVs.
Add report/mark_hidden_devices to lvm.conf.
Use brackets consistently in report fields to mark hidden devices.
Restore background polling processing during auto-activation (2.02.119).
Fix invalid memory read when reporting cache LV policy_name (2.02.126).
Version 2.02.139 - 8th January 2016
===================================
Update lvmlockd with the new VG seqno before devices are suspended.
Rework vgrename to use the common processing code in toollib.
Make pvs show new devices on the system since the last .cache update.
Document F,D and M thin pool health status chars for lv_attr in lvs man page.
Also add lvm2-activation{-early,-net}.service systemd status for lvmdump -s.
Version 2.02.138 - 14th December 2015
=====================================
Support lvrename for hidden (used) cache pools.
Fix lvrename for stacked cache pools.
Version 2.02.137 - 5th December 2015
====================================
Restore archiving before changing metadata in vgextend (2.02.117).
Dropped internal usage of log_suppress(2).
Cleaned logging code for buffer size usage.
Added internal id_read_format_try() function to check and read valid UUID.
Change lvcreate, lvrename, lvresize to use process_each_vg.
Change process_each_vg to handle single VG as separate arg.
Issue error if ambiguous VG name is supplied in most commands.
Make process_each fns always work through full list of known VG names.
Use dm_get_status_mirror() instead of individual parsers.
Add mem pool arg for check_transient_status() target function.
Avoid misleading error with -m is omitted with lvconvert to raid types.
Add system_id to vginfo cache.
Version 2.02.136 - 28th November 2015
=====================================
Add new --sinceversion option for lvmconfig --type new.
Fix inactive table loaded for wrapping thin-pool when resizing it.
Extend the list of ignored libraries when locking memory.
Version 2.02.135 - 23rd November 2015
=====================================
Add a model file for Coverity.
Show correct error message for unsupported yet cache pool repair.
Allow lvconvert cache pools' data and metadata LV to raid.
Fix reading of old metadata with missing cache policy or mode settings.
Issue error if external_device_info_source=udev and udev db record incomplete.
Update lvmetad duplicate VG name handling to use hash function extensions.
Detect invalid vgrenames by vgid where the name is unchanged.
Fix passing of 32bit values through daemons (mostly lvmlockd).
Use local memory pool for whole alloc_handle manipulation.
Add missing pointer validation after dm_get_next_target().
Do not deref NULL pointer in debug message for _match_pv_tags().
Drop unneeded stat() call when checking for sysfs file.
Fix memory leak on error path of failing thin-pool percentage check.
Add missing test for failing node allocation in lvmetad.
Correct configure messages when enabling/disabling lvmlockd.
Version 2.02.134 - 9th November 2015
====================================
Refactor some lvmetad code and adjust some duplicate PV messages.
No longer repair/wipe VG/PVs if inaccessible because foreign or shared.
Pass correct data size to mirror log calc so log can be bigger than 1 extent.
Version 2.02.133 - 30th October 2015
====================================

View File

@ -1,5 +1,93 @@
Version 1.02.111 -
Version 1.02.128 - 25th June 2016
=================================
Recognize 'all' keyword used in selection as synonym for "" (no selection).
Add dm_report_set_selection to set selection for multiple output of report.
Add DM_REPORT_OUTPUT_MULTIPLE_TIMES flag for multiple output of same report.
Move field width handling/sort init from dm_report_object to dm_report_output.
Add _LOG_BYPASS_REPORT flag for bypassing any log report currently set.
Introduce DM_REPORT_GROUP_JSON for report group with JSON output format.
Introduce DM_REPORT_GROUP_BASIC for report group with basic report output.
Introduce DM_REPORT_GROUP_SINGLE for report group having single report only.
Add dm_report_group_{create,push,pop,destroy} to support report grouping.
Version 1.02.127 - 11th June 2016
=================================
Fix blkdeactivate regression causing skipping of dm + md devices. (1.02.126)
Version 1.02.126 - 3rd June 2016
================================
Report passthrough caching mode when parsing cache mode.
Version 1.02.125 - 14th May 2016
================================
Show library version in message even if dm driver version is unavailable.
Version 1.02.124 - 30th April 2016
==================================
Add dm_udev_wait_immediate to libdevmapper for waiting outside the library.
Version 1.02.123 - 23rd April 2016
==================================
Do not strip LVM- when debug reporting not found uuid.
Version 1.02.122 - 9th April 2016
=================================
Change log_debug ioctl flags from single characters into words.
Version 1.02.121 - 26th March 2016
==================================
Adjust raid status function.
Version 1.02.120 - 11th March 2016
==================================
Improve parsing of cache status and report Fail, Error, needs_check, ro.
Version 1.02.119 - 4th March 2016
=================================
Fix dm_config_write_node and variants to return error on subsection failures.
Remove 4096 char limit due to buffer size if writing dm_config_node.
Version 1.02.118 - 26th February 2016
=====================================
Fix string boundary check in _get_canonical_field_name().
Always initialized hist struct in _stats_parse_histogram().
Version 1.02.117 - 21st February 2016
=====================================
Improve status parsing for thin-pool and thin devices.
Version 1.02.116 - 15th February 2016
=====================================
Use fully aligned allocations for dm_pool_strdup/strndup() (1.02.64).
Fix thin-pool table parameter feature order to match kernel output.
Version 1.02.115 - 25th January 2016
====================================
Fix man page for dmsetup udevcreatecookie.
Version 1.02.114 - 14th December 2015
=====================================
Better support for dmsetup static linkage.
Extend validity checks on dmeventd client socket.
Version 1.02.113 - 5th December 2015
====================================
Mirror plugin in dmeventd uses dm_get_status_mirror().
Add dm_get_status_mirror() for parsing mirror status line.
Version 1.02.112 - 28th November 2015
=====================================
Show error message when trying to create unsupported raid type.
Improve preloading sequence of an active thin-pool target.
Drop extra space from cache target line to fix unneded table reloads.
Version 1.02.111 - 23rd November 2015
=====================================
Extend dm_hash to support multiple values with the same key.
Add missing check for allocation inside dm_split_lvm_name().
Test dm_task_get_message_response for !NULL in dm_stats_print_region().
Add checks for failing dm_stats_create() in dmsetup.
Add missing fifo close when failed to initialize client connection.
Version 1.02.110 - 30th October 2015
====================================
@ -29,7 +117,7 @@ Version 1.02.110 - 30th October 2015
Correct use of max_write_behind parameter when generating raid target line.
Fix dm-event systemd service to make sure it is executed before mounting.
Version 1.02.109 - 22nd September 2016
Version 1.02.109 - 22nd September 2015
======================================
Update man pages for dmsetup and dmstats.
Improve help text for dmsetup.

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,6 +11,17 @@
# Refer to 'man lvm.conf' for further information about profiles and
# general configuration file layout.
#
allocation {
cache_mode="writethrough"
cache_settings {
}
}
log {
report_command_log=0
command_log_sort="log_seq_num"
command_log_cols="log_seq_num,log_type,log_context,log_object_type,log_object_name,log_object_id,log_object_group,log_object_group_id,log_message,log_errno,log_ret_code"
command_log_selection="!(log_type=status && message=success)"
}
global {
units="h"
si_unit_consistency=1
@ -18,7 +29,9 @@ global {
lvdisplay_shows_full_device_path=0
}
report {
output_format="basic"
compact_output=0
compact_output_cols=""
aligned=1
buffered=1
headings=1
@ -28,6 +41,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 +60,15 @@ report {
pvsegs_sort="pv_name,pvseg_start"
pvsegs_cols="pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size"
pvsegs_cols_verbose="pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size,lv_name,seg_start_pe,segtype,seg_pe_ranges"
vgs_cols_full="vg_all"
pvs_cols_full="pv_all"
lvs_cols_full="lv_all"
pvsegs_cols_full="pvseg_all,pv_uuid,lv_uuid"
segs_cols_full="seg_all,lv_uuid"
vgs_sort_full="vg_name"
pvs_sort_full="pv_name"
lvs_sort_full="vg_name,lv_name"
pvsegs_sort_full="pv_uuid,pvseg_start"
segs_sort_full="lv_uuid,seg_start"
mark_hidden_devices=1
}

View File

@ -299,6 +299,19 @@ devices {
# generally do. If enabled, discards will only be issued if both the
# storage and kernel provide support.
issue_discards = 0
# Configuration option devices/allow_changes_with_duplicate_pvs.
# Allow VG modification while a PV appears on multiple devices.
# When a PV appears on multiple devices, LVM attempts to choose the
# best device to use for the PV. If the devices represent the same
# underlying storage, the choice has minimal consequence. If the
# devices represent different underlying storage, the wrong choice
# can result in data loss if the VG is modified. Disabling this
# setting is the safest option because it prevents modifying a VG
# or activating LVs in it while a PV appears on multiple devices.
# Enabling this setting allows the VG to be used as usual even with
# uncertain devices.
allow_changes_with_duplicate_pvs = 0
}
# Configuration section allocation.
@ -465,6 +478,55 @@ allocation {
# How LVM log information is reported.
log {
# Configuration option log/report_command_log.
# Enable or disable LVM log reporting.
# If enabled, LVM will collect a log of operations, messages,
# per-object return codes with object identification and associated
# error numbers (errnos) during LVM command processing. Then the
# log is either reported solely or in addition to any existing
# reports, depending on LVM command used. If it is a reporting command
# (e.g. pvs, vgs, lvs, lvm fullreport), then the log is reported in
# addition to any existing reports. Otherwise, there's only log report
# on output. For all applicable LVM commands, you can request that
# the output has only log report by using --logonly command line
# option. Use log/command_log_cols and log/command_log_sort settings
# to define fields to display and sort fields for the log report.
# You can also use log/command_log_selection to define selection
# criteria used each time the log is reported.
# This configuration option has an automatic default value.
# report_command_log = 0
# Configuration option log/command_log_sort.
# List of columns to sort by when reporting command log.
# See <lvm command> --logonly --configreport log -o help
# for the list of possible fields.
# This configuration option has an automatic default value.
# command_log_sort = "log_seq_num"
# Configuration option log/command_log_cols.
# List of columns to report when reporting command log.
# See <lvm command> --logonly --configreport log -o help
# for the list of possible fields.
# This configuration option has an automatic default value.
# command_log_cols = "log_seq_num,log_type,log_context,log_object_type,log_object_name,log_object_id,log_object_group,log_object_group_id,log_message,log_errno,log_ret_code"
# Configuration option log/command_log_selection.
# Selection criteria used when reporting command log.
# You can define selection criteria that are applied each
# time log is reported. This way, it is possible to control the
# amount of log that is displayed on output and you can select
# only parts of the log that are important for you. To define
# selection criteria, use fields from log report. See also
# <lvm command> --logonly --configreport log -S help for the
# list of possible fields and selection operators. You can also
# define selection criteria for log report on command line directly
# using <lvm command> --configreport log -S <selection criteria>
# which has precedence over log/command_log_selection setting.
# For more information about selection criteria in general, see
# lvm(8) man page.
# This configuration option has an automatic default value.
# command_log_selection = "!(log_type=status && message=success)"
# Configuration option log/verbose.
# Controls the messages sent to stdout or stderr.
verbose = 0
@ -525,7 +587,7 @@ log {
# debug output if the class is listed here. Classes currently
# available: memory, devices, activation, allocation, lvmetad,
# metadata, cache, locking, lvmpolld. Use "all" to see everything.
debug_classes = [ "memory", "devices", "activation", "allocation", "lvmetad", "metadata", "cache", "locking", "lvmpolld" ]
debug_classes = [ "memory", "devices", "activation", "allocation", "lvmetad", "metadata", "cache", "locking", "lvmpolld", "dbus" ]
}
# Configuration section backup.
@ -851,13 +913,23 @@ global {
# devices/global_filter.
use_lvmetad = @DEFAULT_USE_LVMETAD@
# Configuration option global/lvmetad_update_wait_time.
# The number of seconds a command will wait for lvmetad update to finish.
# After waiting for this period, a command will not use lvmetad, and
# will revert to disk scanning.
# This configuration option has an automatic default value.
# lvmetad_update_wait_time = 10
# Configuration option global/use_lvmlockd.
# Use lvmlockd for locking among hosts using LVM on shared storage.
# See lvmlockd(8) for more information.
# Applicable only if LVM is compiled with lockd support in which
# case there is also lvmlockd(8) man page available for more
# information.
use_lvmlockd = 0
# Configuration option global/lvmlockd_lock_retries.
# Retry lvmlockd lock requests this many times.
# Applicable only if LVM is compiled with lockd support
# This configuration option has an automatic default value.
# lvmlockd_lock_retries = 3
@ -867,7 +939,8 @@ global {
# LVs have been created, the internal LV needs to be extended. lvcreate
# will automatically extend the internal LV when needed by the amount
# specified here. Setting this to 0 disables the automatic extension
# and can cause lvcreate to fail.
# and can cause lvcreate to fail. Applicable only if LVM is compiled
# with lockd support
# This configuration option has an automatic default value.
# sanlock_lv_extend = 256
@ -1014,7 +1087,14 @@ global {
# a native systemd service, which allows it to be started on demand,
# and to use its own control group. When this option is disabled, LVM
# commands will supervise long running operations by forking themselves.
# Applicable only if LVM is compiled with lvmpolld support.
use_lvmpolld = @DEFAULT_USE_LVMPOLLD@
# Configuration option global/notify_dbus.
# Enable D-Bus notification from LVM commands.
# When enabled, an LVM command that changes PVs, changes VG metadata,
# or changes the activation state of an LV will send a notification.
notify_dbus = 1
}
# Configuration section activation.
@ -1109,8 +1189,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 +1226,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 +1252,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 +1495,33 @@ 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/record_lvs_history.
# When enabled, LVM keeps history records about removed LVs in
# metadata. The information that is recorded in metadata for
# historical LVs is reduced when compared to original
# information kept in metadata for live LVs. Currently, this
# feature is supported for thin and thin snapshot LVs only.
# This configuration option has an automatic default value.
# record_lvs_history = 0
# Configuration option metadata/lvs_history_retention_time.
# Retention time in seconds after which a record about individual
# historical logical volume is automatically destroyed.
# A value of 0 disables this feature.
# This configuration option has an automatic default value.
# lvs_history_retention_time = 0
# Configuration option metadata/pvmetadatacopies.
# Number of copies of metadata to store on each PV.
# The --pvmetadatacopies option overrides this setting.
@ -1493,6 +1600,22 @@ activation {
# This configuration section has an automatic default value.
# report {
# Configuration option report/output_format.
# Format of LVM command's report output.
# If there is more than one report per command, then the format
# is applied for all reports. You can also change output format
# directly on command line using --reportformat option which
# has precedence over log/output_format setting.
# Accepted values:
# basic
# Original format with columns and rows. If there is more than
# one report per command, each report is prefixed with report's
# name for identification.
# json
# JSON format.
# This configuration option has an automatic default value.
# output_format = "basic"
# Configuration option report/compact_output.
# Do not print empty values for all report fields.
# If enabled, all fields that don't have a value set for any of the
@ -1808,6 +1931,77 @@ 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/vgs_cols_full.
# List of columns to report for lvm fullreport's 'vgs' subreport.
# See 'vgs -o help' for the list of possible fields.
# This configuration option has an automatic default value.
# vgs_cols_full = "vg_all"
# Configuration option report/pvs_cols_full.
# List of columns to report for lvm fullreport's 'vgs' subreport.
# See 'pvs -o help' for the list of possible fields.
# This configuration option has an automatic default value.
# pvs_cols_full = "pv_all"
# Configuration option report/lvs_cols_full.
# List of columns to report for lvm fullreport's 'lvs' subreport.
# See 'lvs -o help' for the list of possible fields.
# This configuration option has an automatic default value.
# lvs_cols_full = "lv_all"
# Configuration option report/pvsegs_cols_full.
# List of columns to report for lvm fullreport's 'pvseg' subreport.
# See 'pvs --segments -o help' for the list of possible fields.
# This configuration option has an automatic default value.
# pvsegs_cols_full = "pvseg_all,pv_uuid,lv_uuid"
# Configuration option report/segs_cols_full.
# List of columns to report for lvm fullreport's 'seg' subreport.
# See 'lvs --segments -o help' for the list of possible fields.
# This configuration option has an automatic default value.
# segs_cols_full = "seg_all,lv_uuid"
# Configuration option report/vgs_sort_full.
# List of columns to sort by when reporting lvm fullreport's 'vgs' subreport.
# See 'vgs -o help' for the list of possible fields.
# This configuration option has an automatic default value.
# vgs_sort_full = "vg_name"
# Configuration option report/pvs_sort_full.
# List of columns to sort by when reporting lvm fullreport's 'vgs' subreport.
# See 'pvs -o help' for the list of possible fields.
# This configuration option has an automatic default value.
# pvs_sort_full = "pv_name"
# Configuration option report/lvs_sort_full.
# List of columns to sort by when reporting lvm fullreport's 'lvs' subreport.
# See 'lvs -o help' for the list of possible fields.
# This configuration option has an automatic default value.
# lvs_sort_full = "vg_name,lv_name"
# Configuration option report/pvsegs_sort_full.
# List of columns to sort by when reporting for lvm fullreport's 'pvseg' subreport.
# See 'pvs --segments -o help' for the list of possible fields.
# This configuration option has an automatic default value.
# pvsegs_sort_full = "pv_uuid,pvseg_start"
# Configuration option report/segs_sort_full.
# List of columns to sort by when reporting lvm fullreport's 'seg' subreport.
# See 'lvs --segments -o help' for the list of possible fields.
# This configuration option has an automatic default value.
# segs_sort_full = "lv_uuid,seg_start"
# Configuration option report/mark_hidden_devices.
# Use brackets [] to mark hidden devices.
# This configuration option has an automatic default value.
# mark_hidden_devices = 1
# Configuration option report/two_word_unknown_device.
# Use the two words 'unknown device' in place of '[unknown]'.
# This is displayed when the device for a PV is not known.
# This configuration option has an automatic default value.
# two_word_unknown_device = 0
# }
# Configuration section dmeventd.

View File

@ -51,6 +51,7 @@ local {
# Configuration option local/host_id.
# The lvmlockd sanlock host_id.
# This must be unique among all hosts, and must be between 1 and 2000.
# Applicable only if LVM is compiled with lockd support
# This configuration option has an automatic default value.
# host_id = 0
}

1326
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
@ -37,9 +37,8 @@ case "$host_os" in
LDDEPS="$LDDEPS .export.sym"
LIB_SUFFIX=so
DEVMAPPER=yes
LVMETAD=no
LVMPOLLD=no
LVMLOCKD=no
BUILD_LVMETAD=no
BUILD_LVMPOLLD=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.
@ -1129,9 +1129,8 @@ AC_ARG_ENABLE(lvmetad,
AC_HELP_STRING([--enable-lvmetad],
[enable the LVM Metadata Daemon]),
LVMETAD=$enableval)
AC_MSG_RESULT($LVMETAD)
BUILD_LVMETAD=$LVMETAD
test -n "$LVMETAD" && BUILD_LVMETAD=$LVMETAD
AC_MSG_RESULT($BUILD_LVMETAD)
################################################################################
dnl -- Build lvmpolld
@ -1140,11 +1139,12 @@ AC_ARG_ENABLE(lvmpolld,
AC_HELP_STRING([--enable-lvmpolld],
[enable the LVM Polling Daemon]),
LVMPOLLD=$enableval)
AC_MSG_RESULT($LVMPOLLD)
BUILD_LVMPOLLD=$LVMPOLLD
test -n "$LVMPOLLD" && BUILD_LVMPOLLD=$LVMPOLLD
AC_MSG_RESULT($BUILD_LVMPOLLD)
################################################################################
BUILD_LVMLOCKD=no
dnl -- Build lockdsanlock
AC_MSG_CHECKING(whether to build lockdsanlock)
AC_ARG_ENABLE(lockd-sanlock,
@ -1155,14 +1155,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,26 +1173,23 @@ 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)
if test "$BUILD_LVMLOCKD" = yes; then
AS_IF([test -n "$BUILD_LVMPOLLD"], [BUILD_LVMPOLLD=yes; AC_MSG_WARN([Enabling lvmpolld - required by lvmlockd.])])
AS_IF([test -n "$BUILD_LVMETAD"], [BUILD_LVMETAD=yes; AC_MSG_WARN([Enabling lvmetad - required by lvmlockd.])])
AS_IF([test "$LVMPOLLD" = no], [AC_MSG_ERROR([cannot build lvmlockd with --disable-lvmpolld.])])
AS_IF([test "$LVMETAD" = no], [AC_MSG_ERROR([cannot build lvmlockd with --disable-lvmetad.])])
AS_IF([test "$BUILD_LVMPOLLD" = no], [BUILD_LVMPOLLD=yes; AC_MSG_WARN([Enabling lvmpolld - required by lvmlockd.])])
AS_IF([test "$BUILD_LVMETAD" = no], [BUILD_LVMETAD=yes; AC_MSG_WARN([Enabling lvmetad - required by lvmlockd.])])
AC_MSG_CHECKING([defaults for use_lvmlockd])
AC_ARG_ENABLE(use_lvmlockd,
AC_HELP_STRING([--disable-use-lvmlockd],
@ -1275,6 +1268,28 @@ fi
AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMPOLLD, [$DEFAULT_USE_LVMPOLLD],
[Use lvmpolld by default.])
################################################################################
dnl -- Build notifydbus
AC_MSG_CHECKING(whether to build notifydbus)
AC_ARG_ENABLE(notify-dbus,
AC_HELP_STRING([--enable-notify-dbus],
[enable LVM notification using dbus]),
NOTIFYDBUS=$enableval)
AC_MSG_RESULT($NOTIFYDBUS)
BUILD_NOTIFYDBUS=$NOTIFYDBUS
if test "$BUILD_NOTIFYDBUS" = yes; then
AC_DEFINE([NOTIFYDBUS_SUPPORT], 1, [Define to 1 to include code that uses dbus notification.])
LIBS="-lsystemd $LIBS"
fi
################################################################################
dnl -- Look for dbus libraries
if test "$BUILD_NOTIFYDBUS" = yes; then
PKG_CHECK_MODULES(NOTIFY_DBUS, systemd >= 221, [HAVE_NOTIFY_DBUS=yes], $bailout)
fi
################################################################################
dnl -- Enable blkid wiping functionality
@ -1299,7 +1314,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 +1357,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 +1460,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
################################################################################
@ -1863,8 +1933,12 @@ AC_DEFINE_UNQUOTED(DEFAULT_CACHE_SUBDIR, ["$DEFAULT_CACHE_SUBDIR"],
AC_ARG_WITH(default-locking-dir,
AC_HELP_STRING([--with-default-locking-dir=DIR],
[default locking directory [/var/lock/lvm]]),
DEFAULT_LOCK_DIR=$withval, DEFAULT_LOCK_DIR="/var/lock/lvm")
[default locking directory [autodetect_lock_dir/lvm]]),
DEFAULT_LOCK_DIR=$withval,
[AC_MSG_CHECKING(for default lock directory)
DEFAULT_LOCK_DIR="$RUN_DIR/lock/lvm"
test -d "$RUN_DIR/lock" || DEFAULT_LOCK_DIR="/var/lock/lvm"
AC_MSG_RESULT($DEFAULT_LOCK_DIR)])
AC_DEFINE_UNQUOTED(DEFAULT_LOCK_DIR, ["$DEFAULT_LOCK_DIR"],
[Name of default locking directory.])
@ -1911,14 +1985,17 @@ 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)
AC_SUBST(BUILD_LOCKDSANLOCK)
AC_SUBST(BUILD_LOCKDDLM)
AC_SUBST(BUILD_NOTIFYDBUS)
AC_SUBST(CACHE)
AC_SUBST(CFLAGS)
AC_SUBST(CFLOW_CMD)
AC_SUBST(CHMOD)
AC_SUBST(CLDFLAGS)
AC_SUBST(CLDNOWHOLEARCHIVE)
AC_SUBST(CLDWHOLEARCHIVE)
@ -1995,10 +2072,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 +2154,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 +2193,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)) {
@ -827,9 +855,9 @@ int dm_event_get_version(struct dm_event_fifos *fifos, int *version) {
return 1;
}
void dm_event_log_set(int debug_level, int use_syslog)
void dm_event_log_set(int debug_log_level, int use_syslog)
{
_debug_level = debug_level;
_debug_level = debug_log_level;
_use_syslog = use_syslog;
}
@ -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
*/
/*
@ -106,7 +106,7 @@ int dm_event_register_handler(const struct dm_event_handler *dmevh);
int dm_event_unregister_handler(const struct dm_event_handler *dmevh);
/* Set debug level for logging, and whether to log on stdout/stderr or syslog */
void dm_event_log_set(int debug_level, int use_syslog);
void dm_event_log_set(int debug_log_level, int use_syslog);
/* Log messages acroding to current debug level */
__attribute__((format(printf, 6, 0)))

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,13 @@
*
* 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"
#include "activate.h" /* For TARGET_NAME* */
/* FIXME Reformat to 80 char lines. */
@ -31,8 +31,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 +43,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;
@ -167,12 +138,12 @@ void process_event(struct dm_task *dmt,
continue;
}
if (strcmp(target_type, "mirror")) {
if (strcmp(target_type, TARGET_NAME_MIRROR)) {
log_info("%s has unmirrored portion.", device);
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"
@ -148,8 +148,8 @@ static void _umount(const char *device, int major, int minor)
continue; /* can't stat, skip this one */
if (S_ISBLK(st.st_mode) &&
major(st.st_rdev) == major &&
minor(st.st_rdev) == minor) {
(int) major(st.st_rdev) == major &&
(int) minor(st.st_rdev) == minor) {
log_error("Unmounting invalid snapshot %s from %s.", device, words[1]);
if (!_run(UMOUNT_COMMAND, "-fl", words[1], NULL))
log_error("Failed to umount snapshot %s from %s: %s.",

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

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)

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

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

View File

@ -0,0 +1,669 @@
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from subprocess import Popen, PIPE
import time
import threading
from itertools import chain
import collections
try:
from . import cfg
from .utils import pv_dest_ranges, log_debug, log_error
from .lvm_shell_proxy import LVMShellProxy
except SystemError:
import cfg
from utils import pv_dest_ranges, log_debug, log_error
from lvm_shell_proxy import LVMShellProxy
SEP = '{|}'
total_time = 0.0
total_count = 0
# We need to prevent different threads from using the same lvm shell
# at the same time.
cmd_lock = threading.RLock()
# The actual method which gets called to invoke the lvm command, can vary
# from forking a new process to using lvm shell
_t_call = None
class LvmExecutionMeta(object):
def __init__(self, start, ended, cmd, ec, stdout_txt, stderr_txt):
self.start = start
self.ended = ended
self.cmd = cmd
self.ec = ec
self.stdout_txt = stdout_txt
self.stderr_txt = stderr_txt
def __str__(self):
return "EC= %d for %s\n" \
"STARTED: %f, ENDED: %f\n" \
"STDOUT=%s\n" \
"STDERR=%s\n" % \
(self.ec, str(self.cmd), self.start, self.ended, self.stdout_txt,
self.stderr_txt)
class LvmFlightRecorder(object):
def __init__(self):
self.queue = collections.deque(maxlen=16)
def add(self, lvm_exec_meta):
self.queue.append(lvm_exec_meta)
def dump(self):
with cmd_lock:
log_error("LVM dbus flight recorder START")
for c in self.queue:
log_error(str(c))
log_error("LVM dbus flight recorder END")
cfg.blackbox = LvmFlightRecorder()
def _debug_c(cmd, exit_code, out):
log_error('CMD= %s' % ' '.join(cmd))
log_error(("EC= %d" % exit_code))
log_error(("STDOUT=\n %s\n" % out[0]))
log_error(("STDERR=\n %s\n" % out[1]))
def call_lvm(command, debug=False):
"""
Call an executable and return a tuple of exitcode, stdout, stderr
:param command: Command to execute
:param debug: Dump debug to stdout
"""
# print 'STACK:'
# for line in traceback.format_stack():
# print line.strip()
# Prepend the full lvm executable so that we can run different versions
# in different locations on the same box
command.insert(0, cfg.LVM_CMD)
process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True)
out = process.communicate()
stdout_text = bytes(out[0]).decode("utf-8")
stderr_text = bytes(out[1]).decode("utf-8")
if debug or process.returncode != 0:
_debug_c(command, process.returncode, (stdout_text, stderr_text))
if process.returncode == 0:
if cfg.DEBUG and out[1] and len(out[1]):
log_error('WARNING: lvm is out-putting text to STDERR on success!')
_debug_c(command, process.returncode, (stdout_text, stderr_text))
return process.returncode, stdout_text, stderr_text
def _shell_cfg():
global _t_call
log_debug('Using lvm shell!')
lvm_shell = LVMShellProxy()
_t_call = lvm_shell.call_lvm
if cfg.USE_SHELL:
_shell_cfg()
else:
_t_call = call_lvm
def set_execution(shell):
global _t_call
with cmd_lock:
_t_call = None
if shell:
log_debug('Using lvm shell!')
lvm_shell = LVMShellProxy()
_t_call = lvm_shell.call_lvm
else:
_t_call = call_lvm
def time_wrapper(command, debug=False):
global total_time
global total_count
with cmd_lock:
start = time.time()
results = _t_call(command, debug)
ended = time.time()
total_time += (ended - start)
total_count += 1
cfg.blackbox.add(LvmExecutionMeta(start, ended, command, *results))
return results
call = time_wrapper
# Default cmd
# Place default arguments for every command here.
def _dc(cmd, args):
c = [cmd, '--noheading', '--separator', '%s' % SEP, '--nosuffix',
'--unbuffered', '--units', 'b']
c.extend(args)
return c
def parse(out):
rc = []
for line in out.split('\n'):
# This line includes separators, so process them
if SEP in line:
elem = line.split(SEP)
cleaned_elem = []
for e in elem:
e = e.strip()
cleaned_elem.append(e)
if len(cleaned_elem) > 1:
rc.append(cleaned_elem)
else:
t = line.strip()
if len(t) > 0:
rc.append(t)
return rc
def parse_column_names(out, column_names):
lines = parse(out)
rc = []
for i in range(0, len(lines)):
d = dict(list(zip(column_names, lines[i])))
rc.append(d)
return rc
def options_to_cli_args(options):
rc = []
for k, v in list(dict(options).items()):
if k.startswith("-"):
rc.append(k)
else:
rc.append("--%s" % k)
if v != "":
rc.append(str(v))
return rc
def pv_remove(device, remove_options):
cmd = ['pvremove']
cmd.extend(options_to_cli_args(remove_options))
cmd.append(device)
return call(cmd)
def _tag(operation, what, add, rm, tag_options):
cmd = [operation]
cmd.extend(options_to_cli_args(tag_options))
if isinstance(what, list):
cmd.extend(what)
else:
cmd.append(what)
if add:
cmd.extend(list(chain.from_iterable(('--addtag', x) for x in add)))
if rm:
cmd.extend(list(chain.from_iterable(('--deltag', x) for x in rm)))
return call(cmd, False)
def pv_tag(pv_devices, add, rm, tag_options):
return _tag('pvchange', pv_devices, add, rm, tag_options)
def vg_tag(vg_name, add, rm, tag_options):
return _tag('vgchange', vg_name, add, rm, tag_options)
def lv_tag(lv_name, add, rm, tag_options):
return _tag('lvchange', lv_name, add, rm, tag_options)
def vg_rename(vg, new_name, rename_options):
cmd = ['vgrename']
cmd.extend(options_to_cli_args(rename_options))
cmd.extend([vg, new_name])
return call(cmd)
def vg_remove(vg_name, remove_options):
cmd = ['vgremove']
cmd.extend(options_to_cli_args(remove_options))
cmd.extend(['-f', vg_name])
return call(cmd)
def vg_lv_create(vg_name, create_options, name, size_bytes, pv_dests):
cmd = ['lvcreate']
cmd.extend(options_to_cli_args(create_options))
cmd.extend(['--size', str(size_bytes) + 'B'])
cmd.extend(['--name', name, vg_name])
pv_dest_ranges(cmd, pv_dests)
return call(cmd)
def vg_lv_snapshot(vg_name, snapshot_options, name, size_bytes):
cmd = ['lvcreate']
cmd.extend(options_to_cli_args(snapshot_options))
cmd.extend(["-s"])
if size_bytes != 0:
cmd.extend(['--size', str(size_bytes) + 'B'])
cmd.extend(['--name', name, vg_name])
return call(cmd)
def vg_lv_create_linear(vg_name, create_options, name, size_bytes, thin_pool):
cmd = ['lvcreate']
cmd.extend(options_to_cli_args(create_options))
if not thin_pool:
cmd.extend(['--size', str(size_bytes) + 'B'])
else:
cmd.extend(['--thin', '--size', str(size_bytes) + 'B'])
cmd.extend(['--name', name, vg_name])
return call(cmd)
def vg_lv_create_striped(vg_name, create_options, name, size_bytes,
num_stripes, stripe_size_kb, thin_pool):
cmd = ['lvcreate']
cmd.extend(options_to_cli_args(create_options))
if not thin_pool:
cmd.extend(['--size', str(size_bytes) + 'B'])
else:
cmd.extend(['--thin', '--size', str(size_bytes) + 'B'])
cmd.extend(['--stripes', str(num_stripes)])
if stripe_size_kb != 0:
cmd.extend(['--stripesize', str(stripe_size_kb)])
cmd.extend(['--name', name, vg_name])
return call(cmd)
def _vg_lv_create_raid(vg_name, create_options, name, raid_type, size_bytes,
num_stripes, stripe_size_kb):
cmd = ['lvcreate']
cmd.extend(options_to_cli_args(create_options))
cmd.extend(['--type', raid_type])
cmd.extend(['--size', str(size_bytes) + 'B'])
if num_stripes != 0:
cmd.extend(['--stripes', str(num_stripes)])
if stripe_size_kb != 0:
cmd.extend(['--stripesize', str(stripe_size_kb)])
cmd.extend(['--name', name, vg_name])
return call(cmd)
def vg_lv_create_raid(vg_name, create_options, name, raid_type, size_bytes,
num_stripes, stripe_size_kb):
cmd = ['lvcreate']
cmd.extend(options_to_cli_args(create_options))
return _vg_lv_create_raid(vg_name, create_options, name, raid_type,
size_bytes, num_stripes, stripe_size_kb)
def vg_lv_create_mirror(vg_name, create_options, name, size_bytes, num_copies):
cmd = ['lvcreate']
cmd.extend(options_to_cli_args(create_options))
cmd.extend(['--type', 'mirror'])
cmd.extend(['--mirrors', str(num_copies)])
cmd.extend(['--size', str(size_bytes) + 'B'])
cmd.extend(['--name', name, vg_name])
return call(cmd)
def vg_create_cache_pool(md_full_name, data_full_name, create_options):
cmd = ['lvconvert']
cmd.extend(options_to_cli_args(create_options))
cmd.extend(['--type', 'cache-pool', '--force', '-y',
'--poolmetadata', md_full_name, data_full_name])
return call(cmd)
def vg_create_thin_pool(md_full_name, data_full_name, create_options):
cmd = ['lvconvert']
cmd.extend(options_to_cli_args(create_options))
cmd.extend(['--type', 'thin-pool', '--force', '-y',
'--poolmetadata', md_full_name, data_full_name])
return call(cmd)
def lv_remove(lv_path, remove_options):
cmd = ['lvremove']
cmd.extend(options_to_cli_args(remove_options))
cmd.extend(['-f', lv_path])
return call(cmd)
def lv_rename(lv_path, new_name, rename_options):
cmd = ['lvrename']
cmd.extend(options_to_cli_args(rename_options))
cmd.extend([lv_path, new_name])
return call(cmd)
def lv_resize(lv_full_name, size_change, pv_dests,
resize_options):
cmd = ['lvresize', '--force']
cmd.extend(options_to_cli_args(resize_options))
if size_change < 0:
cmd.append("-L-%dB" % (-size_change))
else:
cmd.append("-L+%dB" % (size_change))
cmd.append(lv_full_name)
pv_dest_ranges(cmd, pv_dests)
return call(cmd)
def lv_lv_create(lv_full_name, create_options, name, size_bytes):
cmd = ['lvcreate']
cmd.extend(options_to_cli_args(create_options))
cmd.extend(['--virtualsize', str(size_bytes) + 'B', '-T'])
cmd.extend(['--name', name, lv_full_name])
return call(cmd)
def lv_cache_lv(cache_pool_full_name, lv_full_name, cache_options):
# lvconvert --type cache --cachepool VG/CachePoolLV VG/OriginLV
cmd = ['lvconvert']
cmd.extend(options_to_cli_args(cache_options))
cmd.extend(['--type', 'cache', '--cachepool',
cache_pool_full_name, lv_full_name])
return call(cmd)
def lv_detach_cache(lv_full_name, detach_options, destroy_cache):
cmd = ['lvconvert']
if destroy_cache:
option = '--uncache'
else:
# Currently fairly dangerous
# see: https://bugzilla.redhat.com/show_bug.cgi?id=1248972
option = '--splitcache'
cmd.extend(options_to_cli_args(detach_options))
# needed to prevent interactive questions
cmd.extend(["--yes", "--force"])
cmd.extend([option, lv_full_name])
return call(cmd)
def 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

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

@ -0,0 +1,881 @@
# 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
# Try and build a key for a LV, so that we sort the LVs with least dependencies
# first. This may be error prone because of the flexibility LVM
# provides and what you can stack.
def get_key(i):
name = i['lv_name']
parent = i['lv_parent']
pool = i['pool_lv']
a1 = ""
a2 = ""
if name[0] == '[':
a1 = '#'
# We have a parent
if parent:
# Check if parent is hidden
if parent[0] == '[':
a2 = '##'
else:
a2 = '#'
# If a LV has a pool, then it should be sorted/loaded after the pool
# lv, unless it's a hidden too, then after other hidden, but before visible
if pool:
if pool[0] != '[':
a2 += '~'
else:
a1 = '$' + a1
return "%s%s%s" % (a1, a2, name)
# noinspection PyUnusedLocal
def lvs_state_retrieve(selection, cache_refresh=True):
rc = []
if cache_refresh:
cfg.db.refresh()
# When building up the model, it's best to process LVs with the least
# dependencies to those that are dependant upon other LVs. Otherwise, when
# we are trying to gather information we could be in a position where we
# don't have information available yet.
lvs = sorted(cfg.db.fetch_lvs(selection), key=get_key)
for l in lvs:
rc.append(LvState(
l['lv_uuid'], l['lv_name'],
l['lv_path'], n(l['lv_size']),
l['vg_name'],
l['vg_uuid'], l['pool_lv_uuid'],
l['pool_lv'], l['origin_uuid'], l['origin'],
n32(l['data_percent']), l['lv_attr'],
l['lv_tags'], l['lv_active'], l['data_lv'],
l['metadata_lv'], l['segtype'], l['lv_role'],
l['lv_layout']))
return rc
def load_lvs(lv_name=None, object_path=None, refresh=False, emit_signal=False,
cache_refresh=True):
# noinspection PyUnresolvedReferences
return common(
lvs_state_retrieve,
(LvCommon, Lv, LvThinPool, LvSnapShot),
lv_name, object_path, refresh, emit_signal, cache_refresh)
# noinspection PyPep8Naming,PyUnresolvedReferences,PyUnusedLocal
class LvState(State):
@staticmethod
def _pv_devices(uuid):
rc = []
for pv in sorted(cfg.db.lv_contained_pv(uuid)):
(pv_uuid, pv_name, pv_segs) = pv
pv_obj = cfg.om.get_object_path_by_uuid_lvm_id(
pv_uuid, pv_name, gen_new=False)
rc.append((pv_obj, pv_segs))
return dbus.Array(rc, signature="(oa(tts))")
def vg_name_lookup(self):
return cfg.om.get_object_by_path(self.Vg).Name
@property
def lvm_id(self):
return "%s/%s" % (self.vg_name_lookup(), self.Name)
def identifiers(self):
return (self.Uuid, self.lvm_id)
def _get_hidden_lv(self):
rc = dbus.Array([], "o")
vg_name = self.vg_name_lookup()
for l in cfg.db.hidden_lvs(self.Uuid):
full_name = "%s/%s" % (vg_name, l[1])
op = cfg.om.get_object_path_by_uuid_lvm_id(
l[0], full_name, gen_new=False)
assert op
rc.append(op)
return rc
def __init__(self, Uuid, Name, Path, SizeBytes,
vg_name, vg_uuid, pool_lv_uuid, PoolLv,
origin_uuid, OriginLv, DataPercent, Attr, Tags, active,
data_lv, metadata_lv, segtypes, role, layout):
utils.init_class_from_arguments(self)
# The segtypes is possibly an array with potentially dupes or a single
# value
self._segs = dbus.Array([], signature='s')
if not isinstance(segtypes, list):
self._segs.append(segtypes)
else:
self._segs.extend(set(segtypes))
self.Vg = cfg.om.get_object_path_by_uuid_lvm_id(
vg_uuid, vg_name, vg_obj_path_generate)
self.Devices = LvState._pv_devices(self.Uuid)
if PoolLv:
gen = utils.lv_object_path_method(Name, (Attr, layout, role))
self.PoolLv = cfg.om.get_object_path_by_uuid_lvm_id(
pool_lv_uuid, '%s/%s' % (vg_name, PoolLv),
gen)
else:
self.PoolLv = '/'
if OriginLv:
self.OriginLv = \
cfg.om.get_object_path_by_uuid_lvm_id(
origin_uuid, '%s/%s' % (vg_name, OriginLv),
vg_obj_path_generate)
else:
self.OriginLv = '/'
self.HiddenLvs = self._get_hidden_lv()
@property
def SegType(self):
return self._segs
def _object_path_create(self):
return utils.lv_object_path_method(
self.Name, (self.Attr, self.layout, self.role))
def _object_type_create(self):
if self.Attr[0] == 't':
return LvThinPool
elif self.Attr[0] == 'C':
if 'pool' in self.layout:
return LvCachePool
else:
return LvCacheLv
elif self.Name[0] == '[':
return LvCommon
elif self.OriginLv != '/':
return LvSnapShot
else:
return Lv
def create_dbus_object(self, path):
if not path:
path = cfg.om.get_object_path_by_uuid_lvm_id(
self.Uuid, self.lvm_id, self._object_path_create())
obj_ctor = self._object_type_create()
return obj_ctor(path, self)
def creation_signature(self):
klass = self._object_type_create()
path_method = self._object_path_create()
return (klass, path_method)
# noinspection PyPep8Naming
@utils.dbus_property(LV_COMMON_INTERFACE, 'Uuid', 's')
@utils.dbus_property(LV_COMMON_INTERFACE, 'Name', 's')
@utils.dbus_property(LV_COMMON_INTERFACE, 'Path', 's')
@utils.dbus_property(LV_COMMON_INTERFACE, 'SizeBytes', 't')
@utils.dbus_property(LV_COMMON_INTERFACE, 'DataPercent', 'u')
@utils.dbus_property(LV_COMMON_INTERFACE, 'SegType', 'as')
@utils.dbus_property(LV_COMMON_INTERFACE, 'Vg', 'o')
@utils.dbus_property(LV_COMMON_INTERFACE, 'OriginLv', 'o')
@utils.dbus_property(LV_COMMON_INTERFACE, 'PoolLv', 'o')
@utils.dbus_property(LV_COMMON_INTERFACE, 'Devices', "a(oa(tts))")
@utils.dbus_property(LV_COMMON_INTERFACE, 'HiddenLvs', "ao")
class LvCommon(AutomatedProperties):
_Tags_meta = ("as", LV_COMMON_INTERFACE)
_Roles_meta = ("as", LV_COMMON_INTERFACE)
_IsThinVolume_meta = ("b", LV_COMMON_INTERFACE)
_IsThinPool_meta = ("b", LV_COMMON_INTERFACE)
_Active_meta = ("b", LV_COMMON_INTERFACE)
_VolumeType_meta = ("(ss)", LV_COMMON_INTERFACE)
_Permissions_meta = ("(ss)", LV_COMMON_INTERFACE)
_AllocationPolicy_meta = ("(ss)", LV_COMMON_INTERFACE)
_State_meta = ("(ss)", LV_COMMON_INTERFACE)
_TargetType_meta = ("(ss)", LV_COMMON_INTERFACE)
_Health_meta = ("(ss)", LV_COMMON_INTERFACE)
_FixedMinor_meta = ('b', LV_COMMON_INTERFACE)
_ZeroBlocks_meta = ('b', LV_COMMON_INTERFACE)
_SkipActivation_meta = ('b', LV_COMMON_INTERFACE)
# noinspection PyUnusedLocal,PyPep8Naming
def __init__(self, object_path, object_state):
super(LvCommon, self).__init__(object_path, lvs_state_retrieve)
self.set_interface(LV_COMMON_INTERFACE)
self.state = object_state
@property
def VolumeType(self):
type_map = {'C': 'Cache', 'm': 'mirrored',
'M': 'Mirrored without initial sync', 'o': 'origin',
'O': 'Origin with merging snapshot', 'r': 'raid',
'R': 'Raid without initial sync', 's': 'snapshot',
'S': 'merging Snapshot', 'p': 'pvmove',
'v': 'virtual', 'i': 'mirror or raid image',
'I': 'mirror or raid Image out-of-sync',
'l': 'mirror log device', 'c': 'under conversion',
'V': 'thin Volume', 't': 'thin pool', 'T': 'Thin pool data',
'e': 'raid or pool metadata or pool metadata spare',
'-': 'Unspecified'}
return (self.state.Attr[0], type_map[self.state.Attr[0]])
@property
def Permissions(self):
type_map = {'w': 'writable', 'r': 'read-only',
'R': 'Read-only activation of non-read-only volume',
'-': 'Unspecified'}
return (self.state.Attr[1], type_map[self.state.Attr[1]])
@property
def AllocationPolicy(self):
type_map = {'a': 'anywhere', 'A': 'anywhere locked',
'c': 'contiguous', 'C': 'contiguous locked',
'i': 'inherited', 'I': 'inherited locked',
'l': 'cling', 'L': 'cling locked',
'n': 'normal', 'N': 'normal locked', '-': 'Unspecified'}
return (self.state.Attr[2], type_map[self.state.Attr[2]])
@property
def FixedMinor(self):
return self.state.Attr[3] == 'm'
@property
def State(self):
type_map = {'a': 'active', 's': 'suspended', 'I': 'Invalid snapshot',
'S': 'invalid Suspended snapshot',
'm': 'snapshot merge failed',
'M': 'suspended snapshot (M)erge failed',
'd': 'mapped device present without tables',
'i': 'mapped device present with inactive table',
'X': 'unknown', '-': 'Unspecified'}
return (self.state.Attr[4], type_map[self.state.Attr[4]])
@property
def TargetType(self):
type_map = {'C': 'Cache', 'm': 'mirror', 'r': 'raid',
's': 'snapshot', 't': 'thin', 'u': 'unknown',
'v': 'virtual', '-': 'Unspecified'}
return (self.state.Attr[6], type_map[self.state.Attr[6]])
@property
def ZeroBlocks(self):
return self.state.Attr[7] == 'z'
@property
def Health(self):
type_map = {'p': 'partial', 'r': 'refresh',
'm': 'mismatches', 'w': 'writemostly',
'X': 'X unknown', '-': 'Unspecified'}
return (self.state.Attr[8], type_map[self.state.Attr[8]])
@property
def SkipActivation(self):
return self.state.Attr[9] == 'k'
def vg_name_lookup(self):
return self.state.vg_name_lookup()
def lv_full_name(self):
return "%s/%s" % (self.state.vg_name_lookup(), self.state.Name)
@property
def identifiers(self):
return self.state.identifiers
@property
def Tags(self):
return utils.parse_tags(self.state.Tags)
@property
def Roles(self):
return utils.parse_tags(self.state.role)
@property
def lvm_id(self):
return self.state.lvm_id
@property
def IsThinVolume(self):
return self.state.Attr[0] == 'V'
@property
def IsThinPool(self):
return self.state.Attr[0] == 't'
@property
def Active(self):
return self.state.active == "active"
@dbus.service.method(
dbus_interface=LV_COMMON_INTERFACE,
in_signature='ia{sv}',
out_signature='o')
def _Future(self, tmo, open_options):
raise dbus.exceptions.DBusException(LV_COMMON_INTERFACE, 'Do not use!')
# noinspection PyPep8Naming
class Lv(LvCommon):
def _fetch_hidden(self, name):
# The name is vg/name
full_name = "%s/%s" % (self.vg_name_lookup(), name)
return cfg.om.get_object_path_by_lvm_id(full_name)
def _get_data_meta(self):
# Get the data
return (self._fetch_hidden(self.state.data_lv),
self._fetch_hidden(self.state.metadata_lv))
# noinspection PyUnusedLocal,PyPep8Naming
def __init__(self, object_path, object_state):
super(Lv, self).__init__(object_path, object_state)
self.set_interface(LV_INTERFACE)
self.state = object_state
@staticmethod
def _remove(lv_uuid, lv_name, remove_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
if dbo:
# Remove the LV, if successful then remove from the model
rc, out, err = cmdhandler.lv_remove(lv_name, remove_options)
if rc == 0:
cfg.om.remove_object(dbo, True)
cfg.load()
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(lv_uuid, lv_name))
return '/'
@dbus.service.method(
dbus_interface=LV_INTERFACE,
in_signature='ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def Remove(self, tmo, remove_options, cb, cbe):
r = RequestEntry(
tmo, Lv._remove,
(self.Uuid, self.lvm_id, remove_options),
cb, cbe, False)
cfg.worker_q.put(r)
@staticmethod
def _rename(lv_uuid, lv_name, new_name, rename_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
if dbo:
# Rename the logical volume
rc, out, err = cmdhandler.lv_rename(lv_name, new_name,
rename_options)
if rc == 0:
cfg.load()
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(lv_uuid, lv_name))
return '/'
@dbus.service.method(
dbus_interface=LV_INTERFACE,
in_signature='sia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def Rename(self, name, tmo, rename_options, cb, cbe):
utils.validate_lv_name(LV_INTERFACE, self.vg_name_lookup(), name)
r = RequestEntry(
tmo, Lv._rename,
(self.Uuid, self.lvm_id, name, rename_options),
cb, cbe, False)
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=LV_INTERFACE,
in_signature='o(tt)a(ott)ia{sv}',
out_signature='o')
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 __init__(self, object_path, object_state):
super(LvThinPool, self).__init__(object_path, object_state)
self.set_interface(THIN_POOL_INTERFACE)
self._data_lv, self._metadata_lv = self._get_data_meta()
@property
def DataLv(self):
return self._data_lv
@property
def MetaDataLv(self):
return self._metadata_lv
@staticmethod
def _lv_create(lv_uuid, lv_name, name, size_bytes, create_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
lv_created = '/'
if dbo:
rc, out, err = cmdhandler.lv_lv_create(
lv_name, create_options, name, size_bytes)
if rc == 0:
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
lvs = load_lvs([full_name], emit_signal=True)[0]
for l in lvs:
lv_created = l.dbus_object_path()
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(lv_uuid, lv_name))
return lv_created
@dbus.service.method(
dbus_interface=THIN_POOL_INTERFACE,
in_signature='stia{sv}',
out_signature='(oo)',
async_callbacks=('cb', 'cbe'))
def LvCreate(self, name, size_bytes, tmo, create_options, cb, cbe):
utils.validate_lv_name(THIN_POOL_INTERFACE, self.vg_name_lookup(), name)
r = RequestEntry(
tmo, LvThinPool._lv_create,
(self.Uuid, self.lvm_id, name,
round_size(size_bytes), create_options), cb, cbe)
cfg.worker_q.put(r)
# noinspection PyPep8Naming
class LvCachePool(Lv):
_DataLv_meta = ("o", CACHE_POOL_INTERFACE)
_MetaDataLv_meta = ("o", CACHE_POOL_INTERFACE)
def __init__(self, object_path, object_state):
super(LvCachePool, self).__init__(object_path, object_state)
self.set_interface(CACHE_POOL_INTERFACE)
self._data_lv, self._metadata_lv = self._get_data_meta()
@property
def DataLv(self):
return self._data_lv
@property
def MetaDataLv(self):
return self._metadata_lv
@staticmethod
def _cache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
# Make sure we have a dbus object representing cache pool
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
# Make sure we have dbus object representing lv to cache
lv_to_cache = cfg.om.get_object_by_path(lv_object_path)
if dbo and lv_to_cache:
fcn = lv_to_cache.lv_full_name()
rc, out, err = cmdhandler.lv_cache_lv(
dbo.lv_full_name(), fcn, cache_options)
if rc == 0:
# When we cache an LV, the cache pool and the lv that is getting
# cached need to be removed from the object manager and
# re-created as their interfaces have changed!
cfg.om.remove_object(dbo, emit_signal=True)
cfg.om.remove_object(lv_to_cache, emit_signal=True)
cfg.load()
lv_converted = cfg.om.get_object_path_by_lvm_id(fcn)
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
msg = ""
if not dbo:
dbo += 'CachePool LV with uuid %s and name %s not present!' % \
(lv_uuid, lv_name)
if not lv_to_cache:
dbo += 'LV to cache with object path %s not present!' % \
(lv_object_path)
raise dbus.exceptions.DBusException(LV_INTERFACE, msg)
return lv_converted
@dbus.service.method(
dbus_interface=CACHE_POOL_INTERFACE,
in_signature='oia{sv}',
out_signature='(oo)',
async_callbacks=('cb', 'cbe'))
def CacheLv(self, lv_object, tmo, cache_options, cb, cbe):
r = RequestEntry(
tmo, LvCachePool._cache_lv,
(self.Uuid, self.lvm_id, lv_object,
cache_options), cb, cbe)
cfg.worker_q.put(r)
# noinspection PyPep8Naming
class LvCacheLv(Lv):
_CachePool_meta = ("o", LV_CACHED)
def __init__(self, object_path, object_state):
super(LvCacheLv, self).__init__(object_path, object_state)
self.set_interface(LV_CACHED)
@property
def CachePool(self):
return self.state.PoolLv
@staticmethod
def _detach_lv(lv_uuid, lv_name, detach_options, destroy_cache):
# Make sure we have a dbus object representing cache pool
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
if dbo:
# Get current cache name
cache_pool = cfg.om.get_object_by_path(dbo.CachePool)
rc, out, err = cmdhandler.lv_detach_cache(
dbo.lv_full_name(), detach_options, destroy_cache)
if rc == 0:
# The cache pool gets removed as hidden and put back to
# visible, so lets delete
cfg.om.remove_object(cache_pool, emit_signal=True)
cfg.om.remove_object(dbo, emit_signal=True)
cfg.load()
uncached_lv_path = cfg.om.get_object_path_by_lvm_id(lv_name)
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(lv_uuid, lv_name))
return uncached_lv_path
@dbus.service.method(
dbus_interface=LV_CACHED,
in_signature='bia{sv}',
out_signature='(oo)',
async_callbacks=('cb', 'cbe'))
def DetachCachePool(self, destroy_cache, tmo, detach_options, cb, cbe):
r = RequestEntry(
tmo, LvCacheLv._detach_lv,
(self.Uuid, self.lvm_id, detach_options,
destroy_cache), cb, cbe)
cfg.worker_q.put(r)
# noinspection PyPep8Naming
class LvSnapShot(Lv):
def __init__(self, object_path, object_state):
super(LvSnapShot, self).__init__(object_path, object_state)
self.set_interface(SNAPSHOT_INTERFACE)
@dbus.service.method(
dbus_interface=SNAPSHOT_INTERFACE,
in_signature='ia{sv}',
out_signature='o')
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()

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

@ -0,0 +1,417 @@
#!/usr/bin/env python3
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from collections import OrderedDict
import pprint as prettyprint
import os
try:
from . import cmdhandler
from .utils import log_debug, log_error
except SystemError:
import cmdhandler
from utils import log_debug
class DataStore(object):
def __init__(self):
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:
# Ths user could be using a symlink instead of the actual
# block device, make sure we are using actual block device file
# if the pv name isn't in the lookup
if s not in self.pv_path_to_uuid:
s = os.path.realpath(s)
rc.append(self.pvs[self.pv_path_to_uuid[s]])
return rc
def fetch_vgs(self, vg_name):
if not vg_name:
return self.vgs.values()
else:
rc = []
for s in vg_name:
rc.append(self.vgs[self.vg_name_to_uuid[s]])
return rc
def fetch_lvs(self, lv_names):
try:
if not lv_names:
return self.lvs.values()
else:
rc = []
for s in lv_names:
rc.append(self.lvs[self.lv_full_name_to_uuid[s]])
return rc
except KeyError as ke:
log_error("Key %s not found!" % (str(lv_names)))
log_error("lv name to uuid lookup")
for keys in sorted(self.lv_full_name_to_uuid.keys()):
log_error("%s" % (keys))
log_error("lvs entries by uuid")
for keys in sorted(self.lvs.keys()):
log_error("%s" % (keys))
raise ke
def pv_pe_segments(self, pv_uuid):
pv = self.pvs[pv_uuid]
return list(zip(pv['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())

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

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

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_uuid_lvm_id(
device, device, None, False)
if pv:
raise dbus.exceptions.DBusException(
MANAGER_INTERFACE, "PV Already exists!")
created_pv = []
rc, out, err = cmdhandler.pv_create(create_options, [device])
if rc == 0:
pvs = load_pvs([device], emit_signal=True)[0]
for p in pvs:
created_pv = p.dbus_object_path()
else:
raise dbus.exceptions.DBusException(
MANAGER_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
return created_pv
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,
in_signature='sia{sv}',
out_signature='(oo)',
async_callbacks=('cb', 'cbe'))
def PvCreate(self, device, tmo, create_options, cb, cbe):
utils.validate_device_path(MANAGER_INTERFACE, device)
r = RequestEntry(
tmo, Manager._pv_create,
(device, create_options), cb, cbe)
cfg.worker_q.put(r)
@staticmethod
def _create_vg(name, pv_object_paths, create_options):
pv_devices = []
for p in pv_object_paths:
pv = cfg.om.get_object_by_path(p)
if pv:
pv_devices.append(pv.Name)
else:
raise dbus.exceptions.DBusException(
MANAGER_INTERFACE, 'object path = %s not found' % p)
rc, out, err = cmdhandler.vg_create(create_options, pv_devices, name)
created_vg = "/"
if rc == 0:
vgs = load_vgs([name], emit_signal=True)[0]
for v in vgs:
created_vg = v.dbus_object_path()
# Update the PVS
load_pvs(refresh=True, emit_signal=True, cache_refresh=False)
else:
raise dbus.exceptions.DBusException(
MANAGER_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
return created_vg
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,
in_signature='saoia{sv}',
out_signature='(oo)',
async_callbacks=('cb', 'cbe'))
def VgCreate(self, name, pv_object_paths, tmo, create_options, cb, cbe):
utils.validate_vg_name(MANAGER_INTERFACE, name)
r = RequestEntry(
tmo, Manager._create_vg,
(name, pv_object_paths, create_options,),
cb, cbe)
cfg.worker_q.put(r)
@staticmethod
def _refresh():
utils.log_debug('Manager.Refresh - entry')
# This is a diagnostic and should not be run in normal operation, so
# lets remove the log entries for refresh as it's implied.
rc = cfg.load(log=False)
if rc != 0:
utils.log_debug('Manager.Refresh - exit %d' % (rc),
'bg_black', 'fg_light_red')
else:
utils.log_debug('Manager.Refresh - exit %d' % (rc))
return rc
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,
out_signature='t',
async_callbacks=('cb', 'cbe'))
def Refresh(self, cb, cbe):
"""
Take all the objects we know about and go out and grab the latest
more of a test method at the moment to make sure we are handling object
paths correctly.
:param cb Callback for result
:param cbe Callback for errors
Returns the number of changes, object add/remove/properties changed
"""
r = RequestEntry(-1, Manager._refresh, (), cb, cbe, False)
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,
in_signature='s',
out_signature='o')
def LookUpByLvmId(self, key):
"""
Given a lvm id in one of the forms:
/dev/sda
some_vg
some_vg/some_lv
Oe1rPX-Pf0W-15E5-n41N-ZmtF-jXS0-Osg8fn
return the object path in O(1) time.
:param key: The lookup value
:return: Return the object path. If object not found you will get '/'
"""
p = cfg.om.get_object_path_by_uuid_lvm_id(
key, key, gen_new=False)
if p:
return p
return '/'
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,
in_signature='b')
def UseLvmShell(self, yes_no):
"""
Allow the client to enable/disable lvm shell, used for testing
:param yes_no:
:return: Nothing
"""
cmdhandler.set_execution(yes_no)
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,
in_signature='s', out_signature='i')
def ExternalEvent(self, command):
event_add((command,))
return dbus.Int32(0)
@staticmethod
def _pv_scan(activate, cache, device_path, major_minor, scan_options):
rc, out, err = cmdhandler.pv_scan(
activate, cache, device_path,
major_minor, scan_options)
if rc == 0:
# This could potentially change the state quite a bit, so lets
# update everything to be safe
cfg.load()
return '/'
else:
raise dbus.exceptions.DBusException(
MANAGER_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,
in_signature='bbasa(ii)ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def PvScan(self, activate, cache, device_paths, major_minors,
tmo, scan_options, cb, cbe):
"""
Scan all supported LVM block devices in the system for physical volumes
NOTE: major_minors & device_paths only usable when cache == True
:param activate: If True, activate any newly found LVs
:param cache: If True, update lvmetad
:param device_paths: Array of device paths or empty
:param major_minors: Array of structures (major,minor)
:param tmo: Timeout for operation
:param scan_options: Additional options to pvscan
:param cb: Not visible in API (used for async. callback)
:param cbe: Not visible in API (used for async. error callback)
:return: '/' if operation done, else job path
"""
for d in device_paths:
utils.validate_device_path(MANAGER_INTERFACE, d)
r = RequestEntry(
tmo, Manager._pv_scan,
(activate, cache, device_paths, major_minors,
scan_options), cb, cbe, False)
cfg.worker_q.put(r)
@property
def lvm_id(self):
"""
Intended to be overridden by classes that inherit
"""
return str(id(self))
@property
def Uuid(self):
"""
Intended to be overridden by classes that inherit
"""
import uuid
return uuid.uuid1()

View File

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

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_uuid_lvm_id(
lv_uuid, full_name, path_create)
rc.append((lv_path, segs))
return dbus.Array(rc, signature="(oa(tts))")
# noinspection PyUnusedLocal,PyPep8Naming
def __init__(self, lvm_path, Uuid, Name,
Fmt, SizeBytes, FreeBytes, UsedBytes, DevSizeBytes,
MdaSizeBytes, MdaFreeBytes, BaStart, BaSizeBytes,
PeStart, PeCount, PeAllocCount, attr, Tags, vg_name,
vg_uuid):
utils.init_class_from_arguments(self)
self.pe_segments = cfg.db.pv_pe_segments(Uuid)
self.lv = self._lv_object_list(vg_name)
if vg_name:
self.vg_path = cfg.om.get_object_path_by_uuid_lvm_id(
vg_uuid, vg_name, vg_obj_path_generate)
else:
self.vg_path = '/'
def identifiers(self):
return (self.Uuid, self.lvm_path)
def create_dbus_object(self, path):
if not path:
path = cfg.om.get_object_path_by_uuid_lvm_id(self.Uuid, self.Name,
pv_obj_path_generate)
return Pv(path, self)
# noinspection PyMethodMayBeStatic
def creation_signature(self):
return (Pv, pv_obj_path_generate)
# noinspection PyPep8Naming
@utils.dbus_property(PV_INTERFACE, 'Uuid', 's') # PV UUID/pv_uuid
@utils.dbus_property(PV_INTERFACE, 'Name', 's') # PV/pv_name
@utils.dbus_property(PV_INTERFACE, 'Fmt', 's') # Fmt/pv_fmt
@utils.dbus_property(PV_INTERFACE, 'SizeBytes', 't') # PSize/pv_size
@utils.dbus_property(PV_INTERFACE, 'FreeBytes', 't') # PFree/pv_free
@utils.dbus_property(PV_INTERFACE, 'UsedBytes', 't') # Used/pv_used
@utils.dbus_property(PV_INTERFACE, 'DevSizeBytes', 't') # DevSize/dev_size
@utils.dbus_property(PV_INTERFACE, 'MdaSizeBytes', 't') # PMdaSize/pv_mda_size
@utils.dbus_property(PV_INTERFACE, 'MdaFreeBytes', 't') # PMdaFree/pv_mda_free
@utils.dbus_property(PV_INTERFACE, 'BaStart', 't') # BA start/pv_ba_start
@utils.dbus_property(PV_INTERFACE, 'BaSizeBytes', 't') # BA size/pv_ba_size
@utils.dbus_property(PV_INTERFACE, 'PeStart', 't') # 1st PE/pe_start
@utils.dbus_property(PV_INTERFACE, 'PeCount', 't') # PE/pv_pe_count
@utils.dbus_property(PV_INTERFACE, 'PeAllocCount', 't') # PE Allocation count
class Pv(AutomatedProperties):
# For properties that we need custom handlers we need these, otherwise
# we won't get our introspection data
_Tags_meta = ("as", PV_INTERFACE)
_PeSegments_meta = ("a(tt)", PV_INTERFACE)
_Exportable_meta = ("b", PV_INTERFACE)
_Allocatable_meta = ("b", PV_INTERFACE)
_Missing_meta = ("b", PV_INTERFACE)
_Lv_meta = ("a(oa(tts))", PV_INTERFACE)
_Vg_meta = ("o", PV_INTERFACE)
# noinspection PyUnusedLocal,PyPep8Naming
def __init__(self, object_path, state_obj):
super(Pv, self).__init__(object_path, pvs_state_retrieve)
self.set_interface(PV_INTERFACE)
self.state = state_obj
@staticmethod
def _remove(pv_uuid, pv_name, remove_options):
# Remove the PV, if successful then remove from the model
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(pv_uuid, pv_name)
if dbo:
rc, out, err = cmdhandler.pv_remove(pv_name, remove_options)
if rc == 0:
cfg.om.remove_object(dbo, True)
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
PV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
PV_INTERFACE,
'PV with uuid %s and name %s not present!' %
(pv_uuid, pv_name))
return '/'
@dbus.service.method(
dbus_interface=PV_INTERFACE,
in_signature='ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def Remove(self, tmo, remove_options, cb, cbe):
r = RequestEntry(
tmo, Pv._remove,
(self.Uuid, self.lvm_id, remove_options),
cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
@staticmethod
def _resize(pv_uuid, pv_name, new_size_bytes, resize_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(pv_uuid, pv_name)
if dbo:
rc, out, err = cmdhandler.pv_resize(pv_name, new_size_bytes,
resize_options)
if rc == 0:
dbo.refresh()
else:
raise dbus.exceptions.DBusException(
PV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
PV_INTERFACE,
'PV with uuid %s and name %s not present!' %
(pv_uuid, pv_name))
return '/'
@dbus.service.method(
dbus_interface=PV_INTERFACE,
in_signature='tia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def ReSize(self, new_size_bytes, tmo, resize_options, cb, cbe):
r = RequestEntry(
tmo, Pv._resize,
(self.Uuid, self.lvm_id, round_size(new_size_bytes),
resize_options), cb, cbe, False)
cfg.worker_q.put(r)
@staticmethod
def _allocation_enabled(pv_uuid, pv_name, yes_no, allocation_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(pv_uuid, pv_name)
if dbo:
rc, out, err = cmdhandler.pv_allocatable(
pv_name, yes_no, allocation_options)
if rc == 0:
cfg.load()
else:
raise dbus.exceptions.DBusException(
PV_INTERFACE, 'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
PV_INTERFACE,
'PV with uuid %s and name %s not present!' %
(pv_uuid, pv_name))
return '/'
@dbus.service.method(
dbus_interface=PV_INTERFACE,
in_signature='bia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def AllocationEnabled(self, yes, tmo, allocation_options, cb, cbe):
r = RequestEntry(
tmo, Pv._allocation_enabled,
(self.Uuid, self.lvm_id,
yes, allocation_options),
cb, cbe, False)
cfg.worker_q.put(r)
@property
def Tags(self):
return utils.parse_tags(self.state.Tags)
@property
def PeSegments(self):
if len(self.state.pe_segments):
return self.state.pe_segments
return dbus.Array([], '(tt)')
@property
def Exportable(self):
if self.state.attr[1] == 'x':
return True
return False
@property
def Allocatable(self):
if self.state.attr[0] == 'a':
return True
return False
@property
def Missing(self):
if self.state.attr[2] == 'm':
return True
return False
def object_path(self):
return self._object_path
@property
def lvm_id(self):
return self.state.lvm_id
@property
def identifiers(self):
return self.state.identifiers()
@property
def Lv(self):
return self.state.lv
@property
def Vg(self):
return self.state.vg_path

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

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

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

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))

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

@ -0,0 +1,950 @@
# 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_uuid_lvm_id(
lv_uuid, full_name, gen)
rc.append(lv_path)
return dbus.Array(rc, signature='o')
def _pv_paths_build(self):
rc = []
for p in cfg.db.pvs_in_vg(self.Uuid):
(pv_name, pv_uuid) = p
rc.append(cfg.om.get_object_path_by_uuid_lvm_id(
pv_uuid, pv_name, pv_obj_path_generate))
return dbus.Array(rc, signature='o')
def __init__(self, Uuid, Name, Fmt,
SizeBytes, FreeBytes, SysId, ExtentSizeBytes,
ExtentCount, FreeCount, Profile, MaxLv, MaxPv, PvCount,
LvCount, SnapCount, Seqno, MdaCount, MdaFree,
MdaSizeBytes, MdaUsedCount, attr, tags):
utils.init_class_from_arguments(self)
self.Pvs = self._pv_paths_build()
self.Lvs = self._lv_paths_build()
def create_dbus_object(self, path):
if not path:
path = cfg.om.get_object_path_by_uuid_lvm_id(
self.Uuid, self.Name, vg_obj_path_generate)
return Vg(path, self)
# noinspection PyMethodMayBeStatic
def creation_signature(self):
return (Vg, vg_obj_path_generate)
# noinspection PyPep8Naming
@utils.dbus_property(VG_INTERFACE, 'Uuid', 's')
@utils.dbus_property(VG_INTERFACE, 'Name', 's')
@utils.dbus_property(VG_INTERFACE, 'Fmt', 's')
@utils.dbus_property(VG_INTERFACE, 'SizeBytes', 't', 0)
@utils.dbus_property(VG_INTERFACE, 'FreeBytes', 't', 0)
@utils.dbus_property(VG_INTERFACE, 'SysId', 's')
@utils.dbus_property(VG_INTERFACE, 'ExtentSizeBytes', 't')
@utils.dbus_property(VG_INTERFACE, 'ExtentCount', 't')
@utils.dbus_property(VG_INTERFACE, 'FreeCount', 't')
@utils.dbus_property(VG_INTERFACE, 'Profile', 's')
@utils.dbus_property(VG_INTERFACE, 'MaxLv', 't')
@utils.dbus_property(VG_INTERFACE, 'MaxPv', 't')
@utils.dbus_property(VG_INTERFACE, 'PvCount', 't')
@utils.dbus_property(VG_INTERFACE, 'LvCount', 't')
@utils.dbus_property(VG_INTERFACE, 'SnapCount', 't')
@utils.dbus_property(VG_INTERFACE, 'Seqno', 't')
@utils.dbus_property(VG_INTERFACE, 'MdaCount', 't')
@utils.dbus_property(VG_INTERFACE, 'MdaFree', 't')
@utils.dbus_property(VG_INTERFACE, 'MdaSizeBytes', 't')
@utils.dbus_property(VG_INTERFACE, 'MdaUsedCount', 't')
class Vg(AutomatedProperties):
_Tags_meta = ("as", VG_INTERFACE)
_Pvs_meta = ("ao", VG_INTERFACE)
_Lvs_meta = ("ao", VG_INTERFACE)
_Writeable_meta = ("b", VG_INTERFACE)
_Readable_meta = ("b", VG_INTERFACE)
_Resizeable_meta = ("b", VG_INTERFACE)
_Exportable_meta = ('b', VG_INTERFACE)
_Partial_meta = ('b', VG_INTERFACE)
_AllocContiguous_meta = ('b', VG_INTERFACE)
_AllocCling_meta = ('b', VG_INTERFACE)
_AllocNormal_meta = ('b', VG_INTERFACE)
_AllocAnywhere_meta = ('b', VG_INTERFACE)
_Clustered_meta = ('b', VG_INTERFACE)
# noinspection PyUnusedLocal,PyPep8Naming
def __init__(self, object_path, object_state):
super(Vg, self).__init__(object_path, vgs_state_retrieve)
self.set_interface(VG_INTERFACE)
self._object_path = object_path
self.state = object_state
@staticmethod
def fetch_new_lv(vg_name, lv_name):
cfg.load()
return cfg.om.get_object_by_lvm_id("%s/%s" % (vg_name, lv_name))
@staticmethod
def _rename(uuid, vg_name, new_name, rename_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.vg_rename(vg_name, new_name,
rename_options)
if rc == 0:
cfg.load()
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return '/'
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='sia{sv}', out_signature='o',
async_callbacks=('cb', 'cbe'))
def Rename(self, name, tmo, rename_options, cb, cbe):
utils.validate_vg_name(VG_INTERFACE, name)
r = RequestEntry(tmo, Vg._rename,
(self.state.Uuid, self.state.lvm_id, name,
rename_options), cb, cbe, False)
cfg.worker_q.put(r)
@staticmethod
def _remove(uuid, vg_name, remove_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
# Remove the VG, if successful then remove from the model
rc, out, err = cmdhandler.vg_remove(vg_name, remove_options)
if rc == 0:
# Remove the VG
cfg.om.remove_object(dbo, True)
# If an LV has hidden LVs, things can get quite involved,
# especially if it's the last thin pool to get removed, so
# lets refresh all
cfg.load()
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return '/'
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='ia{sv}', out_signature='o',
async_callbacks=('cb', 'cbe'))
def Remove(self, tmo, remove_options, cb, cbe):
r = RequestEntry(tmo, Vg._remove,
(self.state.Uuid, self.state.lvm_id, remove_options),
cb, cbe, False)
cfg.worker_q.put(r)
@staticmethod
def _change(uuid, vg_name, change_options):
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.vg_change(change_options, vg_name)
# To use an example with d-feet (Method input)
# {"activate": __import__('gi.repository.GLib', globals(),
# locals(), ['Variant']).Variant("s", "n")}
if rc == 0:
cfg.load()
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return '/'
# TODO: This should be broken into a number of different methods
# instead of having one method that takes a hash for parameters. Some of
# the changes that vgchange does works on entire system, not just a
# specfic vg, thus that should be in the Manager interface.
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def Change(self, tmo, change_options, cb, cbe):
r = RequestEntry(tmo, Vg._change,
(self.state.Uuid, self.state.lvm_id, change_options),
cb, cbe, False)
cfg.worker_q.put(r)
@staticmethod
def _reduce(uuid, vg_name, missing, pv_object_paths, reduce_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
pv_devices = []
# If pv_object_paths is not empty, then get the device paths
if pv_object_paths and len(pv_object_paths) > 0:
for pv_op in pv_object_paths:
pv = cfg.om.get_object_by_path(pv_op)
if pv:
pv_devices.append(pv.lvm_id)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'PV Object path not found = %s!' % pv_op)
rc, out, err = cmdhandler.vg_reduce(vg_name, missing, pv_devices,
reduce_options)
if rc == 0:
cfg.load()
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE, 'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return '/'
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='baoia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def Reduce(self, missing, pv_object_paths, tmo, reduce_options, cb, cbe):
r = RequestEntry(tmo, Vg._reduce,
(self.state.Uuid, self.state.lvm_id, missing,
pv_object_paths, reduce_options), cb, cbe, False)
cfg.worker_q.put(r)
@staticmethod
def _extend(uuid, vg_name, pv_object_paths, extend_options):
# Make sure we have a dbus object representing it
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
extend_devices = []
for i in pv_object_paths:
pv = cfg.om.get_object_by_path(i)
if pv:
extend_devices.append(pv.lvm_id)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE, 'PV Object path not found = %s!' % i)
if len(extend_devices):
rc, out, err = cmdhandler.vg_extend(vg_name, extend_devices,
extend_options)
if rc == 0:
cfg.load()
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE, 'No pv_object_paths provided!')
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return '/'
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='aoia{sv}', out_signature='o',
async_callbacks=('cb', 'cbe'))
def Extend(self, pv_object_paths, tmo, extend_options, cb, cbe):
r = RequestEntry(tmo, Vg._extend,
(self.state.Uuid, self.state.lvm_id, pv_object_paths,
extend_options),
cb, cbe, False)
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=VG_INTERFACE,
in_signature='o(tt)a(ott)ia{sv}',
out_signature='o')
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

@ -37,11 +37,12 @@ int main(int argc, char **argv)
printf("lvmetactl dump\n");
printf("lvmetactl pv_list\n");
printf("lvmetactl vg_list\n");
printf("lvmetactl get_global_info\n");
printf("lvmetactl vg_lookup_name <name>\n");
printf("lvmetactl vg_lookup_uuid <uuid>\n");
printf("lvmetactl pv_lookup_uuid <uuid>\n");
printf("lvmetactl set_global_invalid 0|1\n");
printf("lvmetactl get_global_invalid\n");
printf("lvmetactl set_global_disable 0|1\n");
printf("lvmetactl set_vg_version <uuid> <name> <version>\n");
printf("lvmetactl vg_lock_type <uuid>\n");
return -1;
@ -54,18 +55,32 @@ int main(int argc, char **argv)
if (!strcmp(cmd, "dump")) {
reply = daemon_send_simple(h, "dump",
"token = %s", "skip",
"pid = " FMTd64, (int64_t)getpid(),
"cmd = %s", "lvmetactl",
NULL);
printf("%s\n", reply.buffer.mem);
} else if (!strcmp(cmd, "pv_list")) {
reply = daemon_send_simple(h, "pv_list",
"token = %s", "skip",
"pid = " FMTd64, (int64_t)getpid(),
"cmd = %s", "lvmetactl",
NULL);
printf("%s\n", reply.buffer.mem);
} else if (!strcmp(cmd, "vg_list")) {
reply = daemon_send_simple(h, "vg_list",
"token = %s", "skip",
"pid = " FMTd64, (int64_t)getpid(),
"cmd = %s", "lvmetactl",
NULL);
printf("%s\n", reply.buffer.mem);
} else if (!strcmp(cmd, "get_global_info")) {
reply = daemon_send_simple(h, "get_global_info",
"token = %s", "skip",
"pid = " FMTd64, (int64_t)getpid(),
"cmd = %s", "lvmetactl",
NULL);
printf("%s\n", reply.buffer.mem);
@ -77,16 +92,28 @@ 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",
"pid = " FMTd64, (int64_t)getpid(),
"cmd = %s", "lvmetactl",
NULL);
print_reply(reply);
} else if (!strcmp(cmd, "get_global_invalid")) {
reply = daemon_send_simple(h, "get_global_info",
} else if (!strcmp(cmd, "set_global_disable")) {
if (argc < 3) {
printf("set_global_disable 0|1\n");
return -1;
}
val = atoi(argv[2]);
reply = daemon_send_simple(h, "set_global_info",
"global_disable = " FMTd64, (int64_t) val,
"disable_reason = %s", LVMETAD_DISABLE_REASON_DIRECT,
"token = %s", "skip",
"pid = " FMTd64, (int64_t)getpid(),
"cmd = %s", "lvmetactl",
NULL);
printf("%s\n", reply.buffer.mem);
print_reply(reply);
} else if (!strcmp(cmd, "set_vg_version")) {
if (argc < 5) {
@ -106,21 +133,27 @@ 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",
"pid = " FMTd64, (int64_t)getpid(),
"cmd = %s", "lvmetactl",
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",
"pid = " FMTd64, (int64_t)getpid(),
"cmd = %s", "lvmetactl",
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",
"pid = " FMTd64, (int64_t)getpid(),
"cmd = %s", "lvmetactl",
NULL);
} else {
printf("name or uuid required\n");
return -1;
@ -138,6 +171,8 @@ int main(int argc, char **argv)
reply = daemon_send_simple(h, "vg_lookup",
"name = %s", name,
"token = %s", "skip",
"pid = " FMTd64, (int64_t)getpid(),
"cmd = %s", "lvmetactl",
NULL);
printf("%s\n", reply.buffer.mem);
@ -151,6 +186,8 @@ int main(int argc, char **argv)
reply = daemon_send_simple(h, "vg_lookup",
"uuid = %s", uuid,
"token = %s", "skip",
"pid = " FMTd64, (int64_t)getpid(),
"cmd = %s", "lvmetactl",
NULL);
printf("%s\n", reply.buffer.mem);
@ -167,6 +204,8 @@ int main(int argc, char **argv)
reply = daemon_send_simple(h, "vg_lookup",
"uuid = %s", uuid,
"token = %s", "skip",
"pid = " FMTd64, (int64_t)getpid(),
"cmd = %s", "lvmetactl",
NULL);
/* printf("%s\n", reply.buffer.mem); */
@ -193,6 +232,8 @@ int main(int argc, char **argv)
reply = daemon_send_simple(h, "pv_lookup",
"uuid = %s", uuid,
"token = %s", "skip",
"pid = " FMTd64, (int64_t)getpid(),
"cmd = %s", "lvmetactl",
NULL);
printf("%s\n", reply.buffer.mem);

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
@ -19,6 +19,13 @@
#define LVMETAD_SOCKET DEFAULT_RUN_DIR "/lvmetad.socket"
#define LVMETAD_TOKEN_UPDATE_IN_PROGRESS "update in progress"
#define LVMETAD_DISABLE_REASON_DIRECT "DIRECT"
#define LVMETAD_DISABLE_REASON_LVM1 "LVM1"
#define LVMETAD_DISABLE_REASON_DUPLICATES "DUPLICATES"
#define LVMETAD_DISABLE_REASON_VGRESTORE "VGRESTORE"
struct volume_group;
/* Different types of replies we may get from lvmetad. */

File diff suppressed because it is too large Load Diff

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"
@ -75,7 +75,10 @@ int scan(daemon_handle h, char *fn) {
}
char uuid[64];
id_write_format(dev->pvid, uuid, 64);
if (!id_write_format(dev->pvid, uuid, 64)) {
fprintf(stderr, "[C] Failed to format PV UUID for %s", dev_name(dev));
return;
}
fprintf(stderr, "[C] found PV: %s\n", uuid);
struct lvmcache_info *info = (struct lvmcache_info *) label->info;
struct physical_volume pv = { 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

@ -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>
@ -78,7 +77,7 @@ static void save_client_info(char *line)
uint32_t client_id = 0;
char name[MAX_NAME+1] = { 0 };
sscanf(line, "info=client pid=%u fd=%d pi=%d id=%u name=%s",
(void) sscanf(line, "info=client pid=%u fd=%d pi=%d id=%u name=%s",
&pid, &fd, &pi, &client_id, name);
clients[num_clients].client_id = client_id;
@ -111,7 +110,7 @@ static void format_info_ls(char *line)
char lock_args[MAX_ARGS+1] = { 0 };
char lock_type[MAX_NAME+1] = { 0 };
sscanf(line, "info=ls ls_name=%s vg_name=%s vg_uuid=%s vg_sysid=%s vg_args=%s lm_type=%s",
(void) sscanf(line, "info=ls ls_name=%s vg_name=%s vg_uuid=%s vg_sysid=%s vg_args=%s lm_type=%s",
ls_name, vg_name, vg_uuid, vg_sysid, lock_args, lock_type);
if (!first_ls)
@ -132,7 +131,7 @@ static void format_info_ls_action(char *line)
uint32_t pid = 0;
char cl_name[MAX_NAME+1] = { 0 };
sscanf(line, "info=ls_action client_id=%u %s %s op=%s",
(void) sscanf(line, "info=ls_action client_id=%u %s %s op=%s",
&client_id, flags, version, op);
find_client_info(client_id, &pid, cl_name);
@ -148,7 +147,7 @@ static void format_info_r(char *line, char *r_name_out, char *r_type_out)
char sh_count[MAX_NAME+1] = { 0 };
uint32_t ver = 0;
sscanf(line, "info=r name=%s type=%s mode=%s %s version=%u",
(void) sscanf(line, "info=r name=%s type=%s mode=%s %s version=%u",
r_name, r_type, mode, sh_count, &ver);
strcpy(r_name_out, r_name);
@ -186,7 +185,7 @@ static void format_info_lk(char *line, char *r_name, char *r_type)
return;
}
sscanf(line, "info=lk mode=%s version=%u %s client_id=%u",
(void) sscanf(line, "info=lk mode=%s version=%u %s client_id=%u",
mode, &ver, flags, &client_id);
find_client_info(client_id, &pid, cl_name);
@ -222,7 +221,7 @@ static void format_info_r_action(char *line, char *r_name, char *r_type)
return;
}
sscanf(line, "info=r_action client_id=%u %s %s op=%s rt=%s mode=%s %s %s %s",
(void) sscanf(line, "info=r_action client_id=%u %s %s op=%s rt=%s mode=%s %s %s %s",
&client_id, flags, version, op, rt, mode, lm, result, lm_rv);
find_client_info(client_id, &pid, cl_name);
@ -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"
@ -307,7 +306,13 @@ static const char *_syslog_num_to_name(int num)
static uint64_t monotime(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
if (clock_gettime(CLOCK_MONOTONIC, &ts)) {
log_error("clock_gettime failed to get timestamp %s.",
strerror(errno));
ts.tv_sec = 0;
}
return ts.tv_sec;
}
@ -318,7 +323,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 +747,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 +1008,51 @@ 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;
int err;
va_start(ap, id);
/*
* mutex is used because all threads share a single
* lvmetad connection/handle.
*/
pthread_mutex_lock(&lvmetad_mutex);
retry:
if (!lvmetad_connected) {
lvmetad_handle = lvmetad_open(NULL);
if (lvmetad_handle.error || lvmetad_handle.socket_fd < 0) {
err = lvmetad_handle.error ?: lvmetad_handle.socket_fd;
pthread_mutex_unlock(&lvmetad_mutex);
log_error("lvmetad_open reconnect error %d", err);
memset(&reply, 0, sizeof(reply));
reply.error = err;
return reply;
} else {
log_debug("lvmetad reconnected");
lvmetad_connected = 1;
}
}
reply = daemon_send_simple_v(lvmetad_handle, id, ap);
/* lvmetad may have been restarted */
if ((reply.error == ECONNRESET) && (retries < 2)) {
daemon_close(lvmetad_handle);
lvmetad_connected = 0;
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;
@ -1216,10 +1248,6 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
rv = -EREMOVED;
}
if (!lvmetad_connected && inval_meta)
log_debug("S %s R %s res_lock no lvmetad connection to invalidate",
ls->name, r->name);
/*
* r is vglk: tell lvmetad to set the vg invalid
* flag, and provide the new r_version. If lvmetad finds
@ -1235,7 +1263,7 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
* caches, and tell lvmetad to set global invalid to 0.
*/
if (lvmetad_connected && inval_meta && (r->type == LD_RT_VG)) {
if (inval_meta && (r->type == LD_RT_VG)) {
daemon_reply reply;
char *uuid;
@ -1247,32 +1275,28 @@ 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);
daemon_reply_destroy(reply);
}
if (lvmetad_connected && inval_meta && (r->type == LD_RT_GL)) {
if (inval_meta && (r->type == LD_RT_GL)) {
daemon_reply reply;
log_debug("S %s R %s res_lock set lvmetad global invalid",
ls->name, r->name);
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 +1357,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 +1371,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 +1575,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 +2279,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 +2645,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 +3078,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 +3121,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);
@ -3297,7 +3350,10 @@ static void *worker_thread_main(void *arg_in)
while (1) {
pthread_mutex_lock(&worker_mutex);
clock_gettime(CLOCK_REALTIME, &ts);
if (clock_gettime(CLOCK_REALTIME, &ts)) {
log_error("clock_gettime failed.");
ts.tv_sec = ts.tv_nsec = 0;
}
ts.tv_sec += delay_sec;
rv = 0;
act = NULL;
@ -3329,6 +3385,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 +3653,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 +3690,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 +3721,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 +3735,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 +4465,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 +4806,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 +4847,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 +4939,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 +4951,6 @@ out:
free(ls);
}
if (!mutex_unlocked)
pthread_mutex_unlock(&lvmetad_mutex);
return rv;
}
@ -5123,13 +5178,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 +5950,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 +6057,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 uint64_t daemon_test_lv_count;
static int lock_lv_name_from_args(char *vg_args, char *lock_lv_name)
{
@ -277,8 +276,8 @@ static int read_host_id_file(void)
*sep = '\0';
memset(key_str, 0, sizeof(key_str));
memset(val_str, 0, sizeof(val_str));
sscanf(key, "%s", key_str);
sscanf(val, "%s", val_str);
(void) sscanf(key, "%s", key_str);
(void) sscanf(val, "%s", val_str);
if (!strcmp(key_str, "host_id")) {
host_id = atoi(val_str);
@ -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

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