1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-10-01 21:44:22 +03:00

Compare commits

..

44 Commits

Author SHA1 Message Date
David Teigland
0a0d991bb5 lvm shell: clear argv for each command 2017-01-13 12:04:25 -06:00
David Teigland
f98b4f3dc2 help: accept positional args
lvm help <commandname> ...
2017-01-13 12:04:24 -06:00
David Teigland
46ad67b31c fix lvmcmdline warning
declaration of ‘usage’ shadows a globa
2017-01-13 12:04:24 -06:00
David Teigland
6c0dbea70a Makefile: clean up create-command parts 2017-01-13 12:04:19 -06:00
David Teigland
4e9ca81960 man lvm: remove options
all options are now included in commands
2017-01-13 12:04:19 -06:00
David Teigland
bb1f0db3a6 args: add man page descriptions 2017-01-12 16:05:16 -06:00
David Teigland
40ef88f0da args: use uint32 arg for maxphysicalvolumes 2017-01-04 12:16:50 -06:00
David Teigland
2700ee4217 lvconvert: remove unused code 2017-01-04 12:16:50 -06:00
David Teigland
bec892a24f lvconvert: use command defs for raid/mirror types
All lvconvert functionality has been moved out of the
previous monolithic lvconvert code, except conversions
related to raid/mirror/striped/linear.  This switches
that remaining code to be based on command defs, and
standard process_each_lv arg processing.  This final
switch results in quite a bit of dead code that is
also removed.
2017-01-04 12:16:49 -06:00
David Teigland
c590594aa5 tests: use swapmetadata
and some other pool/cache/thin related changes
2017-01-04 12:16:49 -06:00
David Teigland
56ffa0f0dd lvconvert: use command defs for mergemirrors
and route the generic --merge to one of the
specific merge functions
2017-01-04 12:16:49 -06:00
David Teigland
c87d9704f8 toollib: find VG name in option values when needed 2017-01-04 12:16:49 -06:00
David Teigland
f30977d4bf lvconvert: use command defs for thin/cache/pool creation
Everything related to thin and cache.
2017-01-04 12:16:49 -06:00
David Teigland
abb408a22a lvconvert: add startpoll command using command def
This is a new explicit version of 'lvconvert LV'
which has been an obscure way of triggering polling
to be restarted on an LV that was previously converted.
2017-01-04 12:16:49 -06:00
David Teigland
edda3f5202 lvconvert: snapshot: use command definitions
Lift all the snapshot utilities (merge, split, combine)
out of the monolithic lvconvert implementation, using
the command definitions.  The old code associated with
these commands is now unused and will be removed separately.
2017-01-04 12:16:48 -06:00
David Teigland
78df117bdf lvconvert: remove unused calls for repair and replace
repair and replace are no longer called from the
monolithic lvconvert code, so remove the unused code.
2017-01-04 12:16:48 -06:00
David Teigland
1e551f4c78 lvconvert: repair and replace: use command definitions
This lifts the lvconvert --repair and --replace commands
out of the monolithic lvconvert implementation.  The
previous calls into repair/replace can no longer be
reached and will be removed in a separate commit.
2017-01-04 12:16:48 -06:00
David Teigland
773ebc72bb lvchange: make use of command definitions
Reorganize the lvchange code to take advantage of
the command definition, and remove the validation
that is done by the command definintion rules.
2017-01-04 12:16:48 -06:00
David Teigland
33760d3dcc process_each_lv: add check_single_lv function
The new check_single_lv() function is called prior to the
existing process_single_lv().  If the check function returns 0,
the LV will not be processed.

The check_single_lv function is meant to be a standard method
to validate the combination of specific command + specific LV,
and decide if the combination is allowed.  The check_single
function can be used by anything that calls process_each_lv.

As commands are migrated to take advantage of command
definitions, each command definition gets its own entry
point which calls process_each for itself, passing a
pair of check_single/process_single functions which can
be specific to the narrowly defined command def.
2017-01-04 12:16:48 -06:00
David Teigland
b020ce3b6e commands: new method for defining commands
. Define a prototype for every lvm command.
. Match every user command with one definition.
. Generate help text and man pages from them.

The new file command-lines.in defines a prototype for every
unique lvm command.  A unique lvm command is a unique
combination of: command name + required option args +
required positional args.  Each of these prototypes also
includes the optional option args and optional positional
args that the command will accept, a description, and a
unique string ID for the definition.  Any valid command
will match one of the prototypes.

Here's an example of the lvresize command definitions from
command-lines.in, there are three unique lvresize commands:

lvresize --size SizeMB LV
OO: --alloc Alloc, --autobackup Bool, --force,
--nofsck, --nosync, --noudevsync, --reportformat String, --resizefs,
--stripes Number, --stripesize SizeKB, --poolmetadatasize SizeMB
OP: PV ...
ID: lvresize_by_size
DESC: Resize an LV by a specified size.

lvresize LV PV ...
OO: --alloc Alloc, --autobackup Bool, --force,
--nofsck, --nosync, --noudevsync,
--reportformat String, --resizefs, --stripes Number, --stripesize SizeKB
ID: lvresize_by_pv
DESC: Resize an LV by specified PV extents.
FLAGS: SECONDARY_SYNTAX

lvresize --poolmetadatasize SizeMB LV_thinpool
OO: --alloc Alloc, --autobackup Bool, --force,
--nofsck, --nosync, --noudevsync,
--reportformat String, --stripes Number, --stripesize SizeKB
OP: PV ...
ID: lvresize_pool_metadata_by_size
DESC: Resize a pool metadata SubLV by a specified size.

The three commands have separate definitions because they have
different required parameters.  Required parameters are specified
on the first line of the definition.  Optional options are
listed after OO, and optional positional args are listed after OP.

This data is used to generate corresponding command definition
structures for lvm in command-lines.h.  usage/help output is also
auto generated, so it is always in sync with the definitions.

Example of the corresponding generated structure in
command-lines.h for the first lvresize prototype
(these structures are never edited directly):

commands[83].name = "lvresize";
commands[83].command_line_id = "lvresize_by_size";
commands[83].command_line_enum = lvresize_by_size_CMD;
commands[83].fn = lvresize;
commands[83].ro_count = 1;
commands[83].rp_count = 1;
commands[83].oo_count = 22;
commands[83].op_count = 1;
commands[83].cmd_flags = 0;
commands[83].desc = "DESC: Resize an LV by a specified size.";
commands[83].usage = "lvresize --size Number[m|unit] LV"
" [ --resizefs, --poolmetadatasize Number[m|unit], COMMON_OPTIONS ]"
" [ PV ... ]";
commands[83].usage_common =
" [ --alloc contiguous|cling|cling_by_tags|normal|anywhere|inherit, --nosync, --reportformat String, --autobackup y|n, --stripes Number, --stripesize Number[k|unit], --nofsck, --commandprofile String, --config String, --debug, --driverloaded y|n, --help, --profile String, --quiet, --verbose, --version, --yes, --test, --force, --noudevsync ]";
commands[83].required_opt_args[0].opt = size_ARG;
commands[83].required_opt_args[0].def.val_bits = val_enum_to_bit(sizemb_VAL);
commands[83].required_pos_args[0].pos = 1;
commands[83].required_pos_args[0].def.val_bits = val_enum_to_bit(lv_VAL);
commands[83].optional_opt_args[0].opt = commandprofile_ARG;
commands[83].optional_opt_args[0].def.val_bits = val_enum_to_bit(string_VAL);
commands[83].optional_opt_args[1].opt = config_ARG;
commands[83].optional_opt_args[1].def.val_bits = val_enum_to_bit(string_VAL);
commands[83].optional_opt_args[2].opt = debug_ARG;
commands[83].optional_opt_args[3].opt = driverloaded_ARG;
commands[83].optional_opt_args[3].def.val_bits = val_enum_to_bit(bool_VAL);
commands[83].optional_opt_args[4].opt = help_ARG;
commands[83].optional_opt_args[5].opt = profile_ARG;
commands[83].optional_opt_args[5].def.val_bits = val_enum_to_bit(string_VAL);
commands[83].optional_opt_args[6].opt = quiet_ARG;
commands[83].optional_opt_args[7].opt = verbose_ARG;
commands[83].optional_opt_args[8].opt = version_ARG;
commands[83].optional_opt_args[9].opt = yes_ARG;
commands[83].optional_opt_args[10].opt = test_ARG;
commands[83].optional_opt_args[11].opt = alloc_ARG;
commands[83].optional_opt_args[11].def.val_bits = val_enum_to_bit(alloc_VAL);
commands[83].optional_opt_args[12].opt = autobackup_ARG;
commands[83].optional_opt_args[12].def.val_bits = val_enum_to_bit(bool_VAL);
commands[83].optional_opt_args[13].opt = force_ARG;
commands[83].optional_opt_args[14].opt = nofsck_ARG;
commands[83].optional_opt_args[15].opt = nosync_ARG;
commands[83].optional_opt_args[16].opt = noudevsync_ARG;
commands[83].optional_opt_args[17].opt = reportformat_ARG;
commands[83].optional_opt_args[17].def.val_bits = val_enum_to_bit(string_VAL);
commands[83].optional_opt_args[18].opt = resizefs_ARG;
commands[83].optional_opt_args[19].opt = stripes_ARG;
commands[83].optional_opt_args[19].def.val_bits = val_enum_to_bit(number_VAL);
commands[83].optional_opt_args[20].opt = stripesize_ARG;
commands[83].optional_opt_args[20].def.val_bits = val_enum_to_bit(sizekb_VAL);
commands[83].optional_opt_args[21].opt = poolmetadatasize_ARG;
commands[83].optional_opt_args[21].def.val_bits = val_enum_to_bit(sizemb_VAL);
commands[83].optional_pos_args[0].pos = 2;
commands[83].optional_pos_args[0].def.val_bits = val_enum_to_bit(pv_VAL);
commands[83].optional_pos_args[0].def.flags = ARG_DEF_FLAG_MAY_REPEAT;

Every user-entered command is compared against the set of
command structures, and matched with one.  An error is
reported if an entered command does not have the required
parameters for any definition.  The closest match is printed
as a suggestion, and running lvresize --help will display
the usage for each possible lvresize command.

The prototype syntax used for help/man output includes
required --option and positional args on the first line,
and optional --option and positional args enclosed in [ ]
on subsequent lines.

  command_name <required_opt_args> <required_pos_args>
          [ <optional_opt_args> ]
          [ <optional_pos_args> ]

$ lvresize --help
  lvresize - Resize a logical volume

  Resize an LV by a specified size.
  lvresize --size Number[m|unit] LV
        [ --resizefs,
          --poolmetadatasize Number[m|unit],
          COMMON_OPTIONS ]
        [ PV ... ]

  Resize a pool metadata SubLV by a specified size.
  lvresize --poolmetadatasize Number[m|unit] LV_thinpool
        [ COMMON_OPTIONS ]
        [ PV ... ]

  Common options:
        [ --alloc contiguous|cling|cling_by_tags|normal|anywhere|inherit,
          --nosync,
          --reportformat String,
          --autobackup y|n,
          --stripes Number,
          --stripesize Number[k|unit],
          --nofsck,
          --commandprofile String,
          --config String,
          --debug,
          --driverloaded y|n,
          --help,
          --profile String,
          --quiet,
          --verbose,
          --version,
          --yes,
          --test,
          --force,
          --noudevsync ]

  (Use --help --help for usage notes.)

$ lvresize --poolmetadatasize 4
  Failed to find a matching command definition.
  Closest command usage is:
  lvresize --poolmetadatasize Number[m|unit] LV_thinpool

Command definitions that are not to be advertised/suggested
have the flag SECONDARY_SYNTAX.  These commands will not be
printed in the normal help output.

Man page prototypes are also generated from the same original
command definitions, and are always in sync with the code
and help text.

Very early in command execution, a matching command definition
is found.  lvm then knows the operation being done, and that
the provided args conform to the definition.  This will allow
lots of ad hoc checking/validation to be removed throughout
the code.

Each command definition can also be routed to a specific
function to implement it.  The function is associated with
an enum value for the command definition (generated from
the ID string.)  These per-command-definition implementation
functions have not yet been created, so all commands
currently fall back to the existing per-command-name
implementation functions.

Using per-command-definition functions will allow lots of
code to be removed which tries to figure out what the
command is meant to do.  This is currently based on ad hoc
and complicated option analysis.  When using the new
functions, what the command is doing is already known
from the associated command definition.

So, this first phase validates every user-entered command
against the set of command prototypes, then calls the existing
implementation.  The second phase can associate an implementation
function with each definition, and take further advantage of the
known operation to avoid the complicated option analysis.
2017-01-04 12:16:41 -06:00
David Teigland
6f25f2f719 lvmlockd: test mode doesn't work
The --test option is not yet compatible with shared VGs
because changes are made in lvmlockd that cannot be
reversed or faked.
2017-01-03 14:18:15 -06:00
Zdenek Kabelac
1f5dde38a7 cleanup: more use of lvseg_name
Use existing function lvseg_name().
2017-01-03 14:55:16 +01:00
Zdenek Kabelac
dc5bb12956 cleanup: use macros 2017-01-03 14:55:16 +01:00
Zdenek Kabelac
ee784fd28f cleanup: defines 2017-01-03 14:55:16 +01:00
Zdenek Kabelac
377288fe03 cleanup: reuse existing code 2017-01-03 14:55:16 +01:00
Zdenek Kabelac
95d5877f7a cache: add missing udev wait
When we need to clear dirty cache content of cached LV, there
is table reload which usually is shortly followed by next metadata
change.  However  udev  can't (as of now)  process   udev event
while device is 'suspended'.

So whenever sequence of  'suspend/resume/suspend' is needed,
we need to wait first for finishing of 'resume' processing before
starting next 'suspend'. Otherwise there is  'race' danger of triggering
unwantend umount by systemd as  such event will trigger
SYSTEMD_READY=0 state for a moment for such changed device.

Such race is pretty ugly to trace so we may need to review more
sequencies for missing 'sync'.

(Other option is to enhnace 'udev' rules processing to avoid
such dramatic actions to be happening for suspended devices).
2017-01-03 14:55:16 +01:00
Zdenek Kabelac
4fd41cf67f vgchange: max_pv limited to uint32
Solves: https://bugzilla.redhat.com/1280496

The only reasonable behaviour here is to error on
any number out of accepted range (i.e. now numbers
wrapping around with some hidden logic).

As this is plain bug there is no support for
backward compatibility since noone should
set numbers >UINT32_MAX and expect 0 or error
depending on how big number was used....

TODO: more fields might need to be converted.
2017-01-03 14:55:16 +01:00
Zdenek Kabelac
9f65a3f0c5 lvmcmdline: support uint32
Add simple function to wrap usage for only uint32 numbers.
Unlike  'int_arg'  which accepts full range of 64bit number
this function will error on numbers out of this range:

   <0, UINT32_MAX>
2017-01-03 14:55:16 +01:00
Bryn M. Reeves
e75f0b7c77 man: fix name of 'write_time' field in dmstats.8.in 2016-12-25 17:36:35 +00:00
Zdenek Kabelac
96a1943fb8 tests: update test
lvm2 now correctly reports thin_id  after action of merged thin,
but before physical metadata update as we know the merge has happened.
2016-12-23 13:16:35 +01:00
Zdenek Kabelac
14902d1739 validation: temporarily let pass linear with chunk_size
Old pool format seems to be setting chunk_size.
For now let validation pass with this.
2016-12-23 13:16:06 +01:00
Heinz Mauelshagen
95d68f1d0e lvchange: allow a transiently failed RaidLV to be refreshed
Add to commits 87117c2b25 and 0b8bf73a63 to avoid refreshing two
times altogether, thus avoiding issues related to clustered, remotely
activated RaidLV.  Avoid need to repeat "lvchange --refresh RaidLV"
two times as a workaround to refresh a RaidLV.  Fix handles removal
of temporary *-missing-* devices created for any missing segments
in RAID SubLVs during activation.

Because the kernel dm-raid target isn't able to handle transiently
failing devices properly we need
"[dm-devel][PATCH] dm raid: fix transient device failure processing"
as well.

test: add lvchange-raid-transient-failures.sh
      and enhance lvconvert-raid.sh

Resolves: rhbz1025322
Related:  rhbz1265191
Related:  rhbz1399844
Related:  rhbz1404425
2016-12-23 03:41:32 +01:00
Zdenek Kabelac
62be9c8de4 tests: use hold_device_open 2016-12-22 23:37:07 +01:00
Zdenek Kabelac
e1943fc07f tests: add device holding function
Hold device open with sleep and wait till sleep really opens
given devices.
2016-12-22 23:37:07 +01:00
Zdenek Kabelac
1053d46aff tests: workaround failure on fc23 2016-12-22 23:37:07 +01:00
Zdenek Kabelac
dd19b56985 thin: refresh status when error processing fails
When thin-pool processes event and 'lvextend --use-policies' fails
rather capture up-to-date new info as the fullness percentage may
have jumped noticable. This way we could use 'more' correct numbers
when checking for thresholds.
2016-12-22 23:37:07 +01:00
Zdenek Kabelac
77997c7673 report: show proper info for merging origin
When there is 'merging' of an origin in progress, but metadata stil
do provide both origin and snapshot, we should show data from merged
snapshot.  This is important mainly for thin case, where there was
a window, where i.e. 'lvs -o+device_id' would report information
about 'already gone' origin thin LV.

This race window is usually hard to trigger but can be ocasionally hit.
Usually shortly after activation, but before polling process manages
to update metadata after merge.
2016-12-22 23:37:07 +01:00
Zdenek Kabelac
2aee4769b4 snapshot: validate merge has started
Before starting polling process, validate the merge has actually started
so there is not pointless invoke of lvmpolld.

This also fixes reported message from command, so user has
correct info whether merging has already started or
if it's delayed for next activation.
2016-12-22 23:37:07 +01:00
Zdenek Kabelac
95e3dd5fb1 lv: more exact check for merging origin
Merging origin has 'MERGE_LV' and should also have its merging snapshot.
2016-12-22 23:37:07 +01:00
Zdenek Kabelac
9491ab41cd validation: rework segment validation
Move individual segment validation to a separate function
executed for 'complete_vg'.

Move some 'extra' validation bits from 'raid' validation to global
segtype validation (so extending existing normal validation)

TODO: still some test are left to be moved.
Reduce some duplication in validation process - there are still
some left thought so still room for improving overal speed.
2016-12-22 23:37:07 +01:00
Tony Asleson
eacff5c189 lvmdbustest: Print messages if timeout value > 10%
We will dump some informational messages if the time to return when we
specify a timeout exceeds 10% of requested.
2016-12-20 11:06:57 -06:00
Tony Asleson
a7e1f973cc lvmdbusd: Use timeout_add instead
The function timeout_add_seconds has quite a bit of variability.  Using
timeout_add which specifies the timeout in ms instead of seconds.  Testing
shows that this is much more consistent which should improve clients that
are using shorter timeouts for the API and the connection.
2016-12-20 11:06:57 -06:00
Tony Asleson
75568294be lvmdbusd: Use cfg.reload() instead of dbo.refresh
We want to update the data and send out any signals as needed, not just
update the in memory database.
2016-12-20 11:06:57 -06:00
Tony Asleson
6fe6e8053a lvmdbusd: Remove un-needed main thread execution 2016-12-20 11:06:57 -06:00
41 changed files with 2539 additions and 1029 deletions

View File

@@ -1,5 +1,11 @@
Version 2.02.169 - Version 2.02.169 -
===================================== =====================================
Add missing udev sync when flushing dirty cache content.
vgchange -p accepts only uint32 numbers.
Report thin LV date for merged LV when the merge is in progress.
Detect if snapshot merge really started before polling for progress.
Checking LV for merging origin requires also it has merged snapshot.
Extend validation of metadata processing.
Enable usage of cached volumes as snapshot origin LV. Enable usage of cached volumes as snapshot origin LV.
Fix displayed lv name when splitting snapshot (2.02.146). Fix displayed lv name when splitting snapshot (2.02.146).
Warn about command not making metadata backup just once per command. Warn about command not making metadata backup just once per command.

View File

@@ -1,5 +1,6 @@
Version 1.02.138 - Version 1.02.138 -
===================================== =====================================
Thin dmeventd plugin reacts faster on lvextend failure path with umount.
Add dm_stats_bind_from_fd() to bind a stats handle from a file descriptor. Add dm_stats_bind_from_fd() to bind a stats handle from a file descriptor.
Do not try call callback when reverting activation on error path. Do not try call callback when reverting activation on error path.
Fix file mapping for extents with physically adjacent extents. Fix file mapping for extents with physically adjacent extents.

View File

@@ -328,6 +328,7 @@ void process_event(struct dm_task *dmt,
char *params; char *params;
int needs_policy = 0; int needs_policy = 0;
int needs_umount = 0; int needs_umount = 0;
struct dm_task *new_dmt = NULL;
#if THIN_DEBUG #if THIN_DEBUG
log_debug("Watch for tp-data:%.2f%% tp-metadata:%.2f%%.", log_debug("Watch for tp-data:%.2f%% tp-metadata:%.2f%%.",
@@ -346,6 +347,28 @@ void process_event(struct dm_task *dmt,
goto out; goto out;
stack; stack;
/*
* Rather update oldish status
* since after 'command' processing
* percentage info could have changed a lot.
* If we would get above UMOUNT_THRESH
* we would wait for next sigalarm.
*/
if (!(new_dmt = dm_task_create(DM_DEVICE_STATUS)))
goto_out;
if (!dm_task_set_uuid(new_dmt, dm_task_get_uuid(dmt)))
goto_out;
/* Non-blocking status read */
if (!dm_task_no_flush(new_dmt))
log_warn("WARNING: Can't set no_flush for dm status.");
if (!dm_task_run(new_dmt))
goto_out;
dmt = new_dmt;
} }
dm_get_next_target(dmt, next, &start, &length, &target_type, &params); dm_get_next_target(dmt, next, &start, &length, &target_type, &params);
@@ -433,6 +456,9 @@ out:
device, state->fails); device, state->fails);
pthread_kill(pthread_self(), SIGALRM); pthread_kill(pthread_self(), SIGALRM);
} }
if (new_dmt)
dm_task_destroy(new_dmt);
} }
int register_device(const char *device, int register_device(const char *device,

View File

@@ -618,7 +618,7 @@ class Lv(LvCommon):
rc, out, err = cmdhandler.activate_deactivate( rc, out, err = cmdhandler.activate_deactivate(
'lvchange', lv_name, activate, control_flags, options) 'lvchange', lv_name, activate, control_flags, options)
if rc == 0: if rc == 0:
dbo.refresh() cfg.load()
return '/' return '/'
else: else:
raise dbus.exceptions.DBusException( raise dbus.exceptions.DBusException(
@@ -667,7 +667,7 @@ class Lv(LvCommon):
rc, out, err = cmdhandler.lv_tag( rc, out, err = cmdhandler.lv_tag(
lv_name, tags_add, tags_del, tag_options) lv_name, tags_add, tags_del, tag_options)
if rc == 0: if rc == 0:
dbo.refresh() cfg.load()
return '/' return '/'
else: else:
raise dbus.exceptions.DBusException( raise dbus.exceptions.DBusException(

View File

@@ -19,7 +19,6 @@ from .utils import log_error, mt_async_result
class RequestEntry(object): class RequestEntry(object):
def __init__(self, tmo, method, arguments, cb, cb_error, def __init__(self, tmo, method, arguments, cb, cb_error,
return_tuple=True, job_state=None): return_tuple=True, job_state=None):
self.tmo = tmo
self.method = method self.method = method
self.arguments = arguments self.arguments = arguments
self.cb = cb self.cb = cb
@@ -35,31 +34,38 @@ class RequestEntry(object):
self._return_tuple = return_tuple self._return_tuple = return_tuple
self._job_state = job_state self._job_state = job_state
if self.tmo < 0: if tmo < 0:
# Client is willing to block forever # Client is willing to block forever
pass pass
elif tmo == 0: elif tmo == 0:
self._return_job() self._return_job()
else: else:
self.timer_id = GLib.timeout_add_seconds( # Note: using 990 instead of 1000 for second to ms conversion to
tmo, RequestEntry._request_timeout, self) # account for overhead. Goal is to return just before the
# timeout amount has expired. Better to be a little early than
# late.
self.timer_id = GLib.timeout_add(
tmo * 990, RequestEntry._request_timeout, self)
@staticmethod @staticmethod
def _request_timeout(r): def _request_timeout(r):
""" """
Method which gets called when the timer runs out! Method which gets called when the timer runs out!
:param r: RequestEntry which timed out :param r: RequestEntry which timed out
:return: Nothing :return: Result of timer_expired
""" """
r.timer_expired() return r.timer_expired()
def _return_job(self): def _return_job(self):
# Return job is only called when we create a request object or when
# we pop a timer. In both cases we are running in the correct context
# and do not need to schedule the call back in main context.
self._job = Job(self, self._job_state) self._job = Job(self, self._job_state)
cfg.om.register_object(self._job, True) cfg.om.register_object(self._job, True)
if self._return_tuple: if self._return_tuple:
mt_async_result(self.cb, ('/', self._job.dbus_object_path())) self.cb(('/', self._job.dbus_object_path()))
else: else:
mt_async_result(self.cb, self._job.dbus_object_path()) self.cb(self._job.dbus_object_path())
def run_cmd(self): def run_cmd(self):
try: try:

View File

@@ -727,7 +727,7 @@ class Vg(AutomatedProperties):
rc, out, err = cmdhandler.vg_tag( rc, out, err = cmdhandler.vg_tag(
vg_name, tags_add, tags_del, tag_options) vg_name, tags_add, tags_del, tag_options)
if rc == 0: if rc == 0:
dbo.refresh() cfg.load()
return '/' return '/'
else: else:
raise dbus.exceptions.DBusException( raise dbus.exceptions.DBusException(
@@ -780,7 +780,7 @@ class Vg(AutomatedProperties):
if dbo: if dbo:
rc, out, err = method(vg_name, value, options) rc, out, err = method(vg_name, value, options)
if rc == 0: if rc == 0:
dbo.refresh() cfg.load()
return '/' return '/'
else: else:
raise dbus.exceptions.DBusException( raise dbus.exceptions.DBusException(

View File

@@ -358,6 +358,10 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
{ {
return 1; return 1;
} }
int lv_deactivate_any_missing_subdevs(const struct logical_volume *lv)
{
return 1;
}
int pv_uses_vg(struct physical_volume *pv, int pv_uses_vg(struct physical_volume *pv,
struct volume_group *vg) struct volume_group *vg)
{ {
@@ -1936,7 +1940,7 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
/* FIXME specify events */ /* FIXME specify events */
if (!monitor_fn(seg, 0)) { if (!monitor_fn(seg, 0)) {
log_error("%s: %s segment monitoring function failed.", log_error("%s: %s segment monitoring function failed.",
display_lvname(lv), seg->segtype->name); display_lvname(lv), lvseg_name(seg));
return 0; return 0;
} }
} else } else
@@ -2573,6 +2577,77 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
return r; return r;
} }
/* Remove any existing, closed mapped device by @name */
static int _remove_dm_dev_by_name(const char *name)
{
int r = 0;
struct dm_task *dmt;
struct dm_info info;
if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
return_0;
/* Check, if the device exists. */
if (dm_task_set_name(dmt, name) && dm_task_run(dmt) && dm_task_get_info(dmt, &info)) {
dm_task_destroy(dmt);
/* Ignore non-existing or open dm devices */
if (!info.exists || info.open_count)
return 1;
if (!(dmt = dm_task_create(DM_DEVICE_REMOVE)))
return_0;
if (dm_task_set_name(dmt, name))
r = dm_task_run(dmt);
}
dm_task_destroy(dmt);
return r;
}
/* Work all segments of @lv removing any existing, closed "*-missing_N_0" sub devices. */
static int _lv_remove_any_missing_subdevs(struct logical_volume *lv)
{
if (lv) {
uint32_t seg_no = 0;
char name[257];
struct lv_segment *seg;
dm_list_iterate_items(seg, &lv->segments) {
if (seg->area_count != 1)
return_0;
if (dm_snprintf(name, sizeof(name), "%s-%s-missing_%u_0", seg->lv->vg->name, seg->lv->name, seg_no) < 0)
return 0;
if (!_remove_dm_dev_by_name(name))
return 0;
seg_no++;
}
}
return 1;
}
/* Remove any "*-missing_*" sub devices added by the activation layer for an rmate/rimage missing PV mapping */
int lv_deactivate_any_missing_subdevs(const struct logical_volume *lv)
{
uint32_t s;
struct lv_segment *seg = first_seg(lv);
for (s = 0; s < seg->area_count; s++) {
if (seg_type(seg, s) == AREA_LV &&
!_lv_remove_any_missing_subdevs(seg_lv(seg, s)))
return 0;
if (seg->meta_areas && seg_metatype(seg, s) == AREA_LV &&
!_lv_remove_any_missing_subdevs(seg_metalv(seg, s)))
return 0;
}
return 1;
}
/* /*
* Does PV use VG somewhere in its construction? * Does PV use VG somewhere in its construction?
* Returns 1 on failure. * Returns 1 on failure.

View File

@@ -124,6 +124,8 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, const struct logi
int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv); int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv);
int lv_deactivate_any_missing_subdevs(const struct logical_volume *lv);
/* /*
* Returns 1 if info structure has been populated, else 0 on failure. * Returns 1 if info structure has been populated, else 0 on failure.
* When lvinfo* is NULL, it returns 1 if the device is locally active, 0 otherwise. * When lvinfo* is NULL, it returns 1 if the device is locally active, 0 otherwise.

View File

@@ -2493,7 +2493,7 @@ static int _add_target_to_dtree(struct dev_manager *dm,
if (!seg->segtype->ops->add_target_line) { if (!seg->segtype->ops->add_target_line) {
log_error(INTERNAL_ERROR "_emit_target cannot handle " log_error(INTERNAL_ERROR "_emit_target cannot handle "
"segment type %s.", seg->segtype->name); "segment type %s.", lvseg_name(seg));
return 0; return 0;
} }

View File

@@ -398,7 +398,7 @@ int export_extents(struct disk_list *dl, uint32_t lv_num,
if (!(seg->segtype->flags & SEG_FORMAT1_SUPPORT)) { if (!(seg->segtype->flags & SEG_FORMAT1_SUPPORT)) {
log_error("Segment type %s in LV %s: " log_error("Segment type %s in LV %s: "
"unsupported by format1", "unsupported by format1",
seg->segtype->name, lv->name); lvseg_name(seg), lv->name);
return 0; return 0;
} }
if (seg_type(seg, s) != AREA_PV) { if (seg_type(seg, s) != AREA_PV) {

View File

@@ -326,7 +326,7 @@ int validate_lv_cache_create_origin(const struct logical_volume *origin_lv)
lv_is_cow(origin_lv) || lv_is_merging_cow(origin_lv) || lv_is_cow(origin_lv) || lv_is_merging_cow(origin_lv) ||
lv_is_virtual(origin_lv)) { lv_is_virtual(origin_lv)) {
log_error("Cache is not supported with %s segment type of the original logical volume %s.", log_error("Cache is not supported with %s segment type of the original logical volume %s.",
first_seg(origin_lv)->segtype->name, display_lvname(origin_lv)); lvseg_name(first_seg(origin_lv)), display_lvname(origin_lv));
return 0; return 0;
} }
@@ -424,9 +424,15 @@ int lv_cache_wait_for_clean(struct logical_volume *cache_lv, int *is_clean)
/* Switch to cleaner policy to flush the cache */ /* Switch to cleaner policy to flush the cache */
cache_seg->cleaner_policy = 1; cache_seg->cleaner_policy = 1;
/* Reaload kernel with "cleaner" policy */ /* Reload cache volume with "cleaner" policy */
if (!lv_update_and_reload_origin(cache_lv)) if (!lv_update_and_reload_origin(cache_lv))
return_0; return_0;
if (!sync_local_dev_names(cache_lv->vg->cmd)) {
log_error("Failed to sync local devices when clearing cache volume %s.",
display_lvname(cache_lv));
return 0;
}
} }
/* /*
@@ -436,6 +442,12 @@ int lv_cache_wait_for_clean(struct logical_volume *cache_lv, int *is_clean)
if (1) { if (1) {
if (!lv_refresh_suspend_resume(lock_lv)) if (!lv_refresh_suspend_resume(lock_lv))
return_0; return_0;
if (!sync_local_dev_names(cache_lv->vg->cmd)) {
log_error("Failed to sync local devices after final clearing of cache %s.",
display_lvname(cache_lv));
return 0;
}
} }
cache_seg->cleaner_policy = 0; cache_seg->cleaner_policy = 0;

View File

@@ -1418,35 +1418,19 @@ static int _lv_refresh_suspend_resume(const struct logical_volume *lv)
int lv_refresh_suspend_resume(const struct logical_volume *lv) int lv_refresh_suspend_resume(const struct logical_volume *lv)
{ {
/* if (!_lv_refresh_suspend_resume(lv))
* FIXME: return 0;
*
* in case of RAID, refresh the SubLVs before
* refreshing the top-level one in order to cope
* with transient failures of SubLVs.
*/
if (lv_is_raid(lv)) {
if (vg_is_clustered(lv->vg) &&
lv_is_active_remotely(lv)) {
if (!_lv_refresh_suspend_resume(lv))
return 0;
} else {
uint32_t s;
struct lv_segment *seg = first_seg(lv);
for (s = 0; s < seg->area_count; s++) { /*
if (seg_type(seg, s) == AREA_LV && * Remove any transiently activated error
!_lv_refresh_suspend_resume(seg_lv(seg, s))) * devices which arean't used any more.
return 0; */
if (seg->meta_areas && if (lv_is_raid(lv) && !lv_deactivate_any_missing_subdevs(lv)) {
seg_metatype(seg, s) == AREA_LV && log_error("Failed to remove temporary SubLVs from %s", display_lvname(lv));
!_lv_refresh_suspend_resume(seg_metalv(seg, s))) return 0;
return 0;
}
}
} }
return _lv_refresh_suspend_resume(lv); return 1;
} }
/* /*
@@ -3482,7 +3466,7 @@ int lv_add_segment(struct alloc_handle *ah,
region_size)) region_size))
return_0; return_0;
if ((segtype->flags & SEG_CAN_SPLIT) && !lv_merge_segments(lv)) { if (segtype_can_split(segtype) && !lv_merge_segments(lv)) {
log_error("Couldn't merge segments after extending " log_error("Couldn't merge segments after extending "
"logical volume."); "logical volume.");
return 0; return 0;
@@ -4611,7 +4595,7 @@ static int _lvresize_adjust_policy(const struct logical_volume *lv,
if (!policy_amount) { if (!policy_amount) {
log_error("Can't extend %s with %s autoextend percent set to 0%%.", log_error("Can't extend %s with %s autoextend percent set to 0%%.",
display_lvname(lv), first_seg(lv)->segtype->name); display_lvname(lv), lvseg_name(first_seg(lv)));
return 0; return 0;
} }
@@ -7063,7 +7047,7 @@ static int _should_wipe_lv(struct lvcreate_params *lp,
struct logical_volume *lv, int warn) struct logical_volume *lv, int warn)
{ {
/* Unzeroable segment */ /* Unzeroable segment */
if (first_seg(lv)->segtype->flags & SEG_CANNOT_BE_ZEROED) if (seg_cannot_be_zeroed(first_seg(lv)))
return 0; return 0;
/* Thin snapshot need not to be zeroed */ /* Thin snapshot need not to be zeroed */

View File

@@ -71,6 +71,13 @@ int lv_merge_segments(struct logical_volume *lv)
if (error_count++ > ERROR_MAX) \ if (error_count++ > ERROR_MAX) \
goto out goto out
#define seg_error(msg) { \
log_error("LV %s, segment %u invalid: %s for %s segment.", \
seg->lv->name, seg_count, (msg), lvseg_name(seg)); \
if ((*error_count)++ > ERROR_MAX) \
return; \
}
/* /*
* RAID segment property checks. * RAID segment property checks.
* *
@@ -188,44 +195,10 @@ static void _check_non_raid_seg_members(struct lv_segment *seg, int *error_count
{ {
if (seg->origin) /* snap and thin */ if (seg->origin) /* snap and thin */
raid_seg_error("non-zero origin LV"); raid_seg_error("non-zero origin LV");
if (seg->indirect_origin) /* thin */
raid_seg_error("non-zero indirect_origin LV");
if (seg->merge_lv) /* thin */
raid_seg_error("non-zero merge LV");
if (seg->cow) /* snap */ if (seg->cow) /* snap */
raid_seg_error("non-zero cow LV"); raid_seg_error("non-zero cow LV");
if (!dm_list_empty(&seg->origin_list)) /* snap */ if (!dm_list_empty(&seg->origin_list)) /* snap */
raid_seg_error("non-zero origin_list"); raid_seg_error("non-zero origin_list");
if (seg->log_lv)
raid_seg_error("non-zero log LV");
if (seg->segtype_private)
raid_seg_error("non-zero segtype_private");
/* thin members */
if (seg->metadata_lv)
raid_seg_error("non-zero metadata LV");
if (seg->transaction_id)
raid_seg_error("non-zero transaction_id");
if (seg->zero_new_blocks)
raid_seg_error("non-zero zero_new_blocks");
if (seg->discards)
raid_seg_error("non-zero discards");
if (!dm_list_empty(&seg->thin_messages))
raid_seg_error("non-zero thin_messages list");
if (seg->external_lv)
raid_seg_error("non-zero external LV");
if (seg->pool_lv)
raid_seg_error("non-zero pool LV");
if (seg->device_id)
raid_seg_error("non-zero device_id");
/* cache members */
if (seg->cache_mode)
raid_seg_error("non-zero cache_mode");
if (seg->policy_name)
raid_seg_error("non-zero policy_name");
if (seg->policy_settings)
raid_seg_error("non-zero policy_settings");
if (seg->cleaner_policy)
raid_seg_error("non-zero cleaner_policy");
/* replicator members (deprecated) */ /* replicator members (deprecated) */
if (seg->replicator) if (seg->replicator)
raid_seg_error("non-zero replicator"); raid_seg_error("non-zero replicator");
@@ -249,9 +222,6 @@ static void _check_raid_seg(struct lv_segment *seg, int *error_count)
uint32_t area_len, s; uint32_t area_len, s;
/* General checks applying to all RAIDs */ /* General checks applying to all RAIDs */
if (!seg_is_raid(seg))
raid_seg_error("erroneous RAID check");
if (!seg->area_count) if (!seg->area_count)
raid_seg_error("zero area count"); raid_seg_error("zero area count");
@@ -276,9 +246,6 @@ static void _check_raid_seg(struct lv_segment *seg, int *error_count)
return; return;
} }
if (seg->chunk_size)
raid_seg_error_val("non-zero chunk_size", seg->chunk_size);
/* FIXME: should we check any non-RAID segment struct members at all? */ /* FIXME: should we check any non-RAID segment struct members at all? */
_check_non_raid_seg_members(seg, error_count); _check_non_raid_seg_members(seg, error_count);
@@ -329,6 +296,169 @@ static void _check_raid_seg(struct lv_segment *seg, int *error_count)
} }
/* END: RAID segment property checks. */ /* END: RAID segment property checks. */
static void _check_lv_segment(struct logical_volume *lv, struct lv_segment *seg,
unsigned seg_count, int *error_count)
{
struct lv_segment *seg2;
if (lv_is_mirror_image(lv) &&
(!(seg2 = find_mirror_seg(seg)) || !seg_is_mirrored(seg2)))
seg_error("mirror image is not mirrored");
if (seg_is_cache(seg)) {
if (!lv_is_cache(lv))
seg_error("is not flagged as cache LV");
if (!seg->pool_lv) {
seg_error("is missing cache pool LV");
} else if (!lv_is_cache_pool(seg->pool_lv))
seg_error("is not referencing cache pool LV");
} else { /* !cache */
if (seg->cleaner_policy)
seg_error("sets cleaner_policy");
}
if (seg_is_cache_pool(seg)) {
if (!dm_list_empty(&seg->lv->segs_using_this_lv)) {
switch (seg->cache_mode) {
case CACHE_MODE_WRITETHROUGH:
case CACHE_MODE_WRITEBACK:
case CACHE_MODE_PASSTHROUGH:
break;
default:
seg_error("has invalid cache's feature flag")
}
if (!seg->policy_name)
seg_error("is missing cache policy name");
}
} else { /* !cache_pool */
if (seg->cache_mode)
seg_error("sets cache mode");
if (seg->policy_name)
seg_error("sets policy name");
if (seg->policy_settings)
seg_error("sets policy settings");
}
if (!seg_can_error_when_full(seg) && lv_is_error_when_full(lv))
seg_error("does not support flag ERROR_WHEN_FULL.");
if (seg_is_mirrored(seg)) {
/* Check mirror log - which is attached to the mirrored seg */
if (seg->log_lv) {
if (!lv_is_mirror_log(seg->log_lv))
seg_error("log LV is not a mirror log");
if (!(seg2 = first_seg(seg->log_lv)) || (find_mirror_seg(seg2) != seg))
seg_error("log LV does not point back to mirror segment");
}
} else { /* !mirrored */
if (seg->log_lv) {
if (lv_is_raid_image(lv))
seg_error("log LV is not a mirror log or a RAID image");
}
}
if (seg_is_raid(seg))
_check_raid_seg(seg, error_count);
if (seg_is_pool(seg)) {
if ((seg->area_count != 1) || (seg_type(seg, 0) != AREA_LV)) {
seg_error("is missing a pool data LV");
} else if (!(seg2 = first_seg(seg_lv(seg, 0))) || (find_pool_seg(seg2) != seg))
seg_error("data LV does not refer back to pool LV");
if (!seg->metadata_lv) {
seg_error("is missing a pool metadata LV");
} else if (!(seg2 = first_seg(seg->metadata_lv)) || (find_pool_seg(seg2) != seg))
seg_error("metadata LV does not refer back to pool LV");
if (!validate_pool_chunk_size(lv->vg->cmd, seg->segtype, seg->chunk_size))
seg_error("has invalid chunk size.");
} else { /* !thin_pool && !cache_pool */
if (seg->metadata_lv)
seg_error("must not have pool metadata LV set");
}
if (seg_is_thin_pool(seg)) {
if (!lv_is_thin_pool(lv))
seg_error("is not flagged as thin pool LV");
if (lv_is_thin_volume(lv))
seg_error("is a thin volume that must not contain thin pool segment");
} else { /* !thin_pool */
if (seg->zero_new_blocks)
seg_error("sets zero_new_blocks");
if (seg->discards)
seg_error("sets discards");
if (!dm_list_empty(&seg->thin_messages))
seg_error("sets thin_messages list");
}
if (seg_is_thin_volume(seg)) {
if (!lv_is_thin_volume(lv))
seg_error("is not flagged as thin volume LV");
if (lv_is_thin_pool(lv))
seg_error("is a thin pool that must not contain thin volume segment");
if (!seg->pool_lv) {
seg_error("is missing thin pool LV");
} else if (!lv_is_thin_pool(seg->pool_lv))
seg_error("is not referencing thin pool LV");
if (seg->device_id > DM_THIN_MAX_DEVICE_ID)
seg_error("has too large device id");
if (seg->external_lv &&
!lv_is_external_origin(seg->external_lv))
seg_error("external LV is not flagged as a external origin LV");
if (seg->merge_lv) {
if (!lv_is_thin_volume(seg->merge_lv))
seg_error("merge LV is not flagged as a thin LV");
if (!lv_is_merging_origin(seg->merge_lv))
seg_error("merge LV is not flagged as merging");
}
} else { /* !thin */
if (seg->device_id)
seg_error("sets device_id");
if (seg->external_lv)
seg_error("sets external LV");
if (seg->merge_lv)
seg_error("sets merge LV");
if (seg->indirect_origin)
seg_error("sets indirect_origin LV");
}
/* Some multi-seg vars excluded here */
if (!seg_is_cache(seg) &&
!seg_is_thin_volume(seg)) {
if (seg->pool_lv)
seg_error("sets pool LV");
}
if (!seg_is_pool(seg) &&
/* FIXME: format_pool/import_export.c _add_linear_seg() sets chunk_size */
!seg_is_linear(seg) &&
!seg_is_snapshot(seg)) {
if (seg->chunk_size)
seg_error("sets chunk_size");
}
if (!seg_is_thin_pool(seg) &&
!seg_is_thin_volume(seg)) {
if (seg->transaction_id)
seg_error("sets transaction_id");
}
if (!seg_unknown(seg)) {
if (seg->segtype_private)
seg_error("set segtype_private");
}
}
/* /*
* Verify that an LV's segments are consecutive, complete and don't overlap. * Verify that an LV's segments are consecutive, complete and don't overlap.
*/ */
@@ -336,7 +466,7 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
{ {
struct lv_segment *seg, *seg2; struct lv_segment *seg, *seg2;
uint32_t le = 0; uint32_t le = 0;
unsigned seg_count = 0, seg_found; unsigned seg_count = 0, seg_found, external_lv_found = 0;
uint32_t area_multiplier, s; uint32_t area_multiplier, s;
struct seg_list *sl; struct seg_list *sl;
struct glv_list *glvl; struct glv_list *glvl;
@@ -344,80 +474,15 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
struct replicator_site *rsite; struct replicator_site *rsite;
struct replicator_device *rdev; struct replicator_device *rdev;
/* Check LV flags match first segment type */
if (complete_vg) {
if (lv_is_thin_volume(lv)) {
if (dm_list_size(&lv->segments) != 1) {
log_error("LV %s is thin volume without exactly one segment.",
lv->name);
inc_error_count;
} else if (!seg_is_thin_volume(first_seg(lv))) {
log_error("LV %s is thin volume without first thin volume segment.",
lv->name);
inc_error_count;
}
}
if (lv_is_thin_pool(lv)) {
if (dm_list_size(&lv->segments) != 1) {
log_error("LV %s is thin pool volume without exactly one segment.",
lv->name);
inc_error_count;
} else if (!seg_is_thin_pool(first_seg(lv))) {
log_error("LV %s is thin pool without first thin pool segment.",
lv->name);
inc_error_count;
}
}
if (lv_is_pool_data(lv) &&
(!(seg2 = first_seg(lv)) || !(seg2 = find_pool_seg(seg2)) ||
seg2->area_count != 1 || seg_type(seg2, 0) != AREA_LV ||
seg_lv(seg2, 0) != lv)) {
log_error("LV %s: segment 1 pool data LV does not point back to same LV",
lv->name);
inc_error_count;
}
if (lv_is_pool_metadata(lv)) {
if (!(seg2 = first_seg(lv)) || !(seg2 = find_pool_seg(seg2)) ||
seg2->metadata_lv != lv) {
log_error("LV %s: segment 1 pool metadata LV does not point back to same LV",
lv->name);
inc_error_count;
}
if (lv_is_thin_pool_metadata(lv) &&
!strstr(lv->name, "_tmeta")) {
log_error("LV %s: thin pool metadata LV does not use _tmeta",
lv->name);
inc_error_count;
} else if (lv_is_cache_pool_metadata(lv) &&
!strstr(lv->name, "_cmeta")) {
log_error("LV %s: cache pool metadata LV does not use _cmeta",
lv->name);
inc_error_count;
}
}
if (lv_is_external_origin(lv)) {
seg_found = 0;
dm_list_iterate_items(sl, &lv->segs_using_this_lv)
if (sl->seg->external_lv == lv)
seg_found++;
if (seg_found != lv->external_count) {
log_error("LV %s: external origin count does not match.",
lv->name);
inc_error_count;
}
}
}
dm_list_iterate_items(seg, &lv->segments) { dm_list_iterate_items(seg, &lv->segments) {
seg_count++; seg_count++;
if (complete_vg && seg_is_raid(seg)) if (seg->lv != lv) {
_check_raid_seg(seg, &error_count); log_error("LV %s invalid: segment %u is referencing different LV.",
lv->name, seg_count);
inc_error_count;
}
if (seg->le != le) { if (seg->le != le) {
log_error("LV %s invalid: segment %u should begin at " log_error("LV %s invalid: segment %u should begin at "
"LE %" PRIu32 " (found %" PRIu32 ").", "LE %" PRIu32 " (found %" PRIu32 ").",
@@ -435,186 +500,6 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
inc_error_count; inc_error_count;
} }
if (lv_is_error_when_full(lv) &&
!seg_can_error_when_full(seg)) {
log_error("LV %s: segment %u (%s) does not support flag "
"ERROR_WHEN_FULL.", lv->name, seg_count, seg->segtype->name);
inc_error_count;
}
if (complete_vg && seg->log_lv &&
!seg_is_mirrored(seg) && lv_is_raid_image(lv)) {
log_error("LV %s: segment %u log LV %s is not a "
"mirror log or a RAID image",
lv->name, seg_count, seg->log_lv->name);
inc_error_count;
}
/*
* Check mirror log - which is attached to the mirrored seg
*/
if (complete_vg && seg->log_lv && seg_is_mirrored(seg)) {
if (!lv_is_mirror_log(seg->log_lv)) {
log_error("LV %s: segment %u log LV %s is not "
"a mirror log",
lv->name, seg_count, seg->log_lv->name);
inc_error_count;
}
if (!(seg2 = first_seg(seg->log_lv)) ||
find_mirror_seg(seg2) != seg) {
log_error("LV %s: segment %u log LV does not "
"point back to mirror segment",
lv->name, seg_count);
inc_error_count;
}
}
if (complete_vg && lv_is_mirror_image(lv)) {
if (!(seg2 = find_mirror_seg(seg)) ||
!seg_is_mirrored(seg2)) {
log_error("LV %s: segment %u mirror image "
"is not mirrored",
lv->name, seg_count);
inc_error_count;
}
}
/* Check the various thin segment types */
if (complete_vg) {
if (seg_is_thin_pool(seg)) {
if (!lv_is_thin_pool(lv)) {
log_error("LV %s is missing thin pool flag for segment %u",
lv->name, seg_count);
inc_error_count;
}
if (lv_is_thin_volume(lv)) {
log_error("LV %s is a thin volume that must not contain thin pool segment %u",
lv->name, seg_count);
inc_error_count;
}
}
if (seg_is_cache_pool(seg) &&
!dm_list_empty(&seg->lv->segs_using_this_lv)) {
switch (seg->cache_mode) {
case CACHE_MODE_WRITETHROUGH:
case CACHE_MODE_WRITEBACK:
case CACHE_MODE_PASSTHROUGH:
break;
default:
log_error("LV %s has invalid cache's feature flag.",
lv->name);
inc_error_count;
}
if (!seg->policy_name) {
log_error("LV %s is missing cache policy name.", lv->name);
inc_error_count;
}
}
if (seg_is_pool(seg)) {
if (seg->area_count != 1 ||
seg_type(seg, 0) != AREA_LV) {
log_error("LV %s: %s segment %u is missing a pool data LV",
lv->name, seg->segtype->name, seg_count);
inc_error_count;
} else if (!(seg2 = first_seg(seg_lv(seg, 0))) || find_pool_seg(seg2) != seg) {
log_error("LV %s: %s segment %u data LV does not refer back to pool LV",
lv->name, seg->segtype->name, seg_count);
inc_error_count;
}
if (!seg->metadata_lv) {
log_error("LV %s: %s segment %u is missing a pool metadata LV",
lv->name, seg->segtype->name, seg_count);
inc_error_count;
} else if (!(seg2 = first_seg(seg->metadata_lv)) ||
find_pool_seg(seg2) != seg) {
log_error("LV %s: %s segment %u metadata LV does not refer back to pool LV",
lv->name, seg->segtype->name, seg_count);
inc_error_count;
}
if (!validate_pool_chunk_size(lv->vg->cmd, seg->segtype, seg->chunk_size)) {
log_error("LV %s: %s segment %u has invalid chunk size %u.",
lv->name, seg->segtype->name, seg_count, seg->chunk_size);
inc_error_count;
}
} else {
if (seg->metadata_lv) {
log_error("LV %s: segment %u must not have pool metadata LV set",
lv->name, seg_count);
inc_error_count;
}
}
if (seg_is_thin_volume(seg)) {
if (!lv_is_thin_volume(lv)) {
log_error("LV %s is missing thin volume flag for segment %u",
lv->name, seg_count);
inc_error_count;
}
if (lv_is_thin_pool(lv)) {
log_error("LV %s is a thin pool that must not contain thin volume segment %u",
lv->name, seg_count);
inc_error_count;
}
if (!seg->pool_lv) {
log_error("LV %s: segment %u is missing thin pool LV",
lv->name, seg_count);
inc_error_count;
} else if (!lv_is_thin_pool(seg->pool_lv)) {
log_error("LV %s: thin volume segment %u pool LV is not flagged as a pool LV",
lv->name, seg_count);
inc_error_count;
}
if (seg->device_id > DM_THIN_MAX_DEVICE_ID) {
log_error("LV %s: thin volume segment %u has too large device id %u",
lv->name, seg_count, seg->device_id);
inc_error_count;
}
if (seg->external_lv && (seg->external_lv->status & LVM_WRITE)) {
log_error("LV %s: external origin %s is writable.",
lv->name, seg->external_lv->name);
inc_error_count;
}
if (seg->merge_lv) {
if (!lv_is_thin_volume(seg->merge_lv)) {
log_error("LV %s: thin volume segment %u merging LV %s is not flagged as a thin LV",
lv->name, seg_count, seg->merge_lv->name);
inc_error_count;
}
if (!lv_is_merging_origin(seg->merge_lv)) {
log_error("LV %s: merging LV %s is not flagged as merging.",
lv->name, seg->merge_lv->name);
inc_error_count;
}
}
} else if (seg_is_cache(seg)) {
if (!lv_is_cache(lv)) {
log_error("LV %s is missing cache flag for segment %u",
lv->name, seg_count);
inc_error_count;
}
if (!seg->pool_lv) {
log_error("LV %s: segment %u is missing cache_pool LV",
lv->name, seg_count);
inc_error_count;
}
} else {
if (seg->pool_lv) {
log_error("LV %s: segment %u must not have pool LV set",
lv->name, seg_count);
inc_error_count;
}
}
}
if (seg_is_snapshot(seg)) { if (seg_is_snapshot(seg)) {
if (seg->cow && seg->cow == seg->origin) { if (seg->cow && seg->cow == seg->origin) {
log_error("LV %s: segment %u has same LV %s for " log_error("LV %s: segment %u has same LV %s for "
@@ -627,6 +512,9 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
if (seg_is_replicator(seg) && !check_replicator_segment(seg)) if (seg_is_replicator(seg) && !check_replicator_segment(seg))
inc_error_count; inc_error_count;
if (complete_vg)
_check_lv_segment(lv, seg, seg_count, &error_count);
for (s = 0; s < seg->area_count; s++) { for (s = 0; s < seg->area_count; s++) {
if (seg_type(seg, s) == AREA_UNASSIGNED) { if (seg_type(seg, s) == AREA_UNASSIGNED) {
log_error("LV %s: segment %u has unassigned " log_error("LV %s: segment %u has unassigned "
@@ -708,6 +596,12 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
le += seg->len; le += seg->len;
} }
if (le != lv->le_count) {
log_error("LV %s: inconsistent LE count %u != %u",
lv->name, le, lv->le_count);
inc_error_count;
}
dm_list_iterate_items(sl, &lv->segs_using_this_lv) { dm_list_iterate_items(sl, &lv->segs_using_this_lv) {
seg = sl->seg; seg = sl->seg;
seg_found = 0; seg_found = 0;
@@ -768,6 +662,10 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
lv->name); lv->name);
inc_error_count; inc_error_count;
} }
/* Validation of external origin counter */
if (seg->external_lv == lv)
external_lv_found++;
} }
dm_list_iterate_items(glvl, &lv->indirect_glvs) { dm_list_iterate_items(glvl, &lv->indirect_glvs) {
@@ -789,10 +687,51 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
} }
} }
if (le != lv->le_count) { /* Check LV flags match first segment type */
log_error("LV %s: inconsistent LE count %u != %u", if (complete_vg) {
lv->name, le, lv->le_count); if ((seg_count != 1) &&
inc_error_count; (lv_is_cache(lv) ||
lv_is_cache_pool(lv) ||
lv_is_raid(lv) ||
lv_is_snapshot(lv) ||
lv_is_thin_pool(lv) ||
lv_is_thin_volume(lv))) {
log_error("LV %s must have exactly one segment.",
lv->name);
inc_error_count;
}
if (lv_is_pool_data(lv) &&
(!(seg2 = first_seg(lv)) || !(seg2 = find_pool_seg(seg2)) ||
seg2->area_count != 1 || seg_type(seg2, 0) != AREA_LV ||
seg_lv(seg2, 0) != lv)) {
log_error("LV %s: segment 1 pool data LV does not point back to same LV",
lv->name);
inc_error_count;
}
if (lv_is_thin_pool_metadata(lv) && !strstr(lv->name, "_tmeta")) {
log_error("LV %s: thin pool metadata LV does not use _tmeta.",
lv->name);
inc_error_count;
} else if (lv_is_cache_pool_metadata(lv) && !strstr(lv->name, "_cmeta")) {
log_error("LV %s: cache pool metadata LV does not use _cmeta.",
lv->name);
inc_error_count;
}
if (lv_is_external_origin(lv)) {
if (lv->external_count != external_lv_found) {
log_error("LV %s: external origin count does not match.",
lv->name);
inc_error_count;
}
if (lv->status & LVM_WRITE) {
log_error("LV %s: external origin cant't be writable.",
lv->name);
inc_error_count;
}
}
} }
out: out:

View File

@@ -198,7 +198,7 @@
#define lv_is_partial(lv) (((lv)->status & PARTIAL_LV) ? 1 : 0) #define lv_is_partial(lv) (((lv)->status & PARTIAL_LV) ? 1 : 0)
#define lv_is_virtual(lv) (((lv)->status & VIRTUAL) ? 1 : 0) #define lv_is_virtual(lv) (((lv)->status & VIRTUAL) ? 1 : 0)
#define lv_is_merging(lv) (((lv)->status & MERGING) ? 1 : 0) #define lv_is_merging(lv) (((lv)->status & MERGING) ? 1 : 0)
#define lv_is_merging_origin(lv) (lv_is_merging(lv)) #define lv_is_merging_origin(lv) (lv_is_merging(lv) && (lv)->snapshot)
#define lv_is_snapshot(lv) (((lv)->status & SNAPSHOT) ? 1 : 0) #define lv_is_snapshot(lv) (((lv)->status & SNAPSHOT) ? 1 : 0)
#define lv_is_converting(lv) (((lv)->status & CONVERTING) ? 1 : 0) #define lv_is_converting(lv) (((lv)->status & CONVERTING) ? 1 : 0)
#define lv_is_external_origin(lv) (((lv)->external_count > 0) ? 1 : 0) #define lv_is_external_origin(lv) (((lv)->external_count > 0) ? 1 : 0)

View File

@@ -5447,6 +5447,19 @@ int vg_flag_write_locked(struct volume_group *vg)
return 0; return 0;
} }
static int _access_vg_clustered(struct cmd_context *cmd, const struct volume_group *vg)
{
if (vg_is_clustered(vg) && !locking_is_clustered()) {
if (!cmd->ignore_clustered_vgs)
log_error("Skipping clustered volume group %s", vg->name);
else
log_verbose("Skipping clustered volume group %s", vg->name);
return 0;
}
return 1;
}
/* /*
* Performs a set of checks against a VG according to bits set in status * Performs a set of checks against a VG according to bits set in status
* and returns FAILED_* bits for those that aren't acceptable. * and returns FAILED_* bits for those that aren't acceptable.
@@ -5458,15 +5471,9 @@ static uint32_t _vg_bad_status_bits(const struct volume_group *vg,
{ {
uint32_t failure = 0; uint32_t failure = 0;
if ((status & CLUSTERED) && if ((status & CLUSTERED) && !_access_vg_clustered(vg->cmd, vg))
(vg_is_clustered(vg)) && !locking_is_clustered()) {
if (!vg->cmd->ignore_clustered_vgs)
log_error("Skipping clustered volume group %s", vg->name);
else
log_verbose("Skipping clustered volume group %s", vg->name);
/* Return because other flags are considered undefined. */ /* Return because other flags are considered undefined. */
return FAILED_CLUSTERED; return FAILED_CLUSTERED;
}
if ((status & EXPORTED_VG) && if ((status & EXPORTED_VG) &&
vg_is_exported(vg)) { vg_is_exported(vg)) {
@@ -5555,19 +5562,6 @@ static int _allow_extra_system_id(struct cmd_context *cmd, const char *system_id
return 0; return 0;
} }
static int _access_vg_clustered(struct cmd_context *cmd, struct volume_group *vg)
{
if (vg_is_clustered(vg) && !locking_is_clustered()) {
if (!cmd->ignore_clustered_vgs)
log_error("Skipping clustered volume group %s", vg->name);
else
log_verbose("Skipping clustered volume group %s", vg->name);
return 0;
}
return 1;
}
static int _access_vg_lock_type(struct cmd_context *cmd, struct volume_group *vg, static int _access_vg_lock_type(struct cmd_context *cmd, struct volume_group *vg,
uint32_t lockd_state, uint32_t *failure) uint32_t lockd_state, uint32_t *failure)
{ {

View File

@@ -2724,15 +2724,6 @@ static const char *_get_segtype_alias(const struct segment_type *segtype)
return ""; return "";
} }
/* Return "linear" for striped segtype with 1 area instead of "striped" */
static const char *_get_segtype_name(const struct segment_type *segtype, unsigned new_image_count)
{
if (!segtype || (segtype_is_striped(segtype) && new_image_count == 1))
return "linear";
return segtype->name;
}
static int _log_possible_conversion_types(const struct logical_volume *lv, const struct segment_type *new_segtype) static int _log_possible_conversion_types(const struct logical_volume *lv, const struct segment_type *new_segtype)
{ {
unsigned possible_conversions = 0; unsigned possible_conversions = 0;
@@ -2753,7 +2744,7 @@ static int _log_possible_conversion_types(const struct logical_volume *lv, const
log_error("Converting %s from %s%s%s%s is " log_error("Converting %s from %s%s%s%s is "
"directly possible to the following layout%s:", "directly possible to the following layout%s:",
display_lvname(lv), _get_segtype_name(seg->segtype, seg->area_count), display_lvname(lv), lvseg_name(seg),
*alias ? " (same as " : "", alias, *alias ? ")" : "", *alias ? " (same as " : "", alias, *alias ? ")" : "",
possible_conversions > 1 ? "s" : ""); possible_conversions > 1 ? "s" : "");

View File

@@ -144,6 +144,12 @@ struct dev_manager;
#define segtype_is_virtual(segtype) ((segtype)->flags & SEG_VIRTUAL ? 1 : 0) #define segtype_is_virtual(segtype) ((segtype)->flags & SEG_VIRTUAL ? 1 : 0)
#define segtype_is_unknown(segtype) ((segtype)->flags & SEG_UNKNOWN ? 1 : 0) #define segtype_is_unknown(segtype) ((segtype)->flags & SEG_UNKNOWN ? 1 : 0)
#define segtype_can_split(segtype) ((segtype)->flags & SEG_CAN_SPLIT ? 1 : 0)
#define segtype_cannot_be_zeroed(segtype) ((segtype)->flags & SEG_CANNOT_BE_ZEROED ? 1 : 0)
#define segtype_monitored(segtype) ((segtype)->flags & SEG_MONITORED ? 1 : 0)
#define segtype_only_exclusive(segtype) ((segtype)->flags & SEG_ONLY_EXCLUSIVE ? 1 : 0)
#define segtype_can_error_when_full(segtype) ((segtype)->flags & SEG_CAN_ERROR_WHEN_FULL ? 1 : 0)
#define segtype_supports_stripe_size(segtype) \ #define segtype_supports_stripe_size(segtype) \
((segtype_is_striped(segtype) || segtype_is_mirror(segtype) || \ ((segtype_is_striped(segtype) || segtype_is_mirror(segtype) || \
segtype_is_cache(segtype) || segtype_is_cache_pool(segtype) || \ segtype_is_cache(segtype) || segtype_is_cache_pool(segtype) || \
@@ -188,11 +194,11 @@ struct dev_manager;
#define seg_is_thin_volume(seg) segtype_is_thin_volume((seg)->segtype) #define seg_is_thin_volume(seg) segtype_is_thin_volume((seg)->segtype)
#define seg_is_virtual(seg) segtype_is_virtual((seg)->segtype) #define seg_is_virtual(seg) segtype_is_virtual((seg)->segtype)
#define seg_unknown(seg) segtype_is_unknown((seg)->segtype) #define seg_unknown(seg) segtype_is_unknown((seg)->segtype)
#define seg_can_split(seg) ((seg)->segtype->flags & SEG_CAN_SPLIT ? 1 : 0) #define seg_can_split(seg) segtype_can_split((seg)->segtype)
#define seg_cannot_be_zeroed(seg) ((seg)->segtype->flags & SEG_CANNOT_BE_ZEROED ? 1 : 0) #define seg_cannot_be_zeroed(seg) segtype_cannot_be_zeroed((seg)->segtype)
#define seg_monitored(seg) ((seg)->segtype->flags & SEG_MONITORED ? 1 : 0) #define seg_monitored(seg) segtype_monitored((seg)->segtype)
#define seg_only_exclusive(seg) ((seg)->segtype->flags & SEG_ONLY_EXCLUSIVE ? 1 : 0) #define seg_only_exclusive(seg) segtype_only_exclusive((seg)->segtype)
#define seg_can_error_when_full(seg) ((seg)->segtype->flags & SEG_CAN_ERROR_WHEN_FULL ? 1 : 0) #define seg_can_error_when_full(seg) segtype_can_error_when_full((seg)->segtype)
struct segment_type { struct segment_type {
struct dm_list list; /* Internal */ struct dm_list list; /* Internal */

View File

@@ -878,7 +878,7 @@ Count of writes merged this interval.
.B write_sector_count .B write_sector_count
Count of 512 byte sectors written this interval. Count of 512 byte sectors written this interval.
.TP .TP
.B write_nsecs .B write_time
Accumulated duration of all write requests (ns). Accumulated duration of all write requests (ns).
.TP .TP
.B in_progress_count .B in_progress_count

View File

@@ -45,6 +45,9 @@ A file containing a simple script with one command per line
can also be given on the command line. The script can also be can also be given on the command line. The script can also be
executed directly if the first line is #! followed by the absolute executed directly if the first line is #! followed by the absolute
path of \fBlvm\fP. path of \fBlvm\fP.
.P
Additional hyphens within option names are ignored. For example,
\fB\-\-readonly\fP and \fB\-\-read\-only\fP are both accepted.
. .
.SH BUILT-IN COMMANDS .SH BUILT-IN COMMANDS
. .
@@ -238,261 +241,6 @@ The following commands are not implemented in LVM2 but might be
in the future: in the future:
.BR lvmsadc ", " lvmsar ", " pvdata . .BR lvmsadc ", " lvmsar ", " pvdata .
. .
.SH OPTIONS
.
The following options are available for many of the commands.
They are implemented generically and documented here rather
than repeated on individual manual pages.
.P
Additional hyphens within option names are ignored. For example,
\fB\-\-readonly\fP and \fB\-\-read\-only\fP are both accepted.
.
.HP
.BR \-h | \-? | \-\-help
.br
Display the help text.
.
.HP
.BR \-\-version
.br
Display version information.
.
.HP
.BR \-v | \-\-verbose
.br
Set verbose level. Repeat from 1 to 3 times to increase the detail
of messages sent to stdout and stderr. Overrides config file setting.
.
.HP
.BR \-d | \-\-debug
.br
Set debug level. Repeat from 1 to 6 times to increase the detail of
messages sent to the log file and/or syslog (if configured).
Overrides config file setting.
.
.HP
.BR \-q | \-\-quiet
.br
Suppress output and log messages.
Overrides \fB\-d\fP and \fB\-v\fP.
Repeat once to also suppress any prompts with answer 'no'.
.
.HP
.BR \-\-yes
.br
Don't prompt for confirmation interactively but instead always assume the
answer is 'yes'. Take great care if you use this!
.
.HP
.BR \-t | \-\-test
.br
Run in test mode. Commands will not update metadata.
This is implemented by disabling all metadata writing but nevertheless
returning success to the calling function. This may lead to unusual
error messages in multi-stage operations if a tool relies on reading
back metadata it believes has changed but hasn't.
.
.HP
.BR \-\-driverloaded
.RB { y | n }
.br
Whether or not the device-mapper kernel driver is loaded.
If you set this to \fBn\fP, no attempt will be made to contact the driver.
.
.HP
.BR \-A | \-\-autobackup
.RB { y | n }
.br
Whether or not to metadata should be backed up automatically after a change.
You are strongly advised not to disable this!
See \fBvgcfgbackup\fP(8).
.
.HP
.BR \-P | \-\-partial
.br
When set, the tools will do their best to provide access to Volume Groups
that are only partially available (one or more Physical Volumes belonging
to the Volume Group are missing from the system). Where part of a logical
volume is missing, \fI\%/dev/ioerror\fP will be substituted, and you could use
\fBdmsetup\fP(8) to set this up to return I/O errors when accessed,
or create it as a large block device of nulls. Metadata may not be
changed with this option. To insert a replacement Physical Volume
of the same or large size use \fBpvcreate \-u\fP to set the uuid to
match the original followed by \fBvgcfgrestore\fP(8).
.
.HP
.BR \-S | \-\-select
.IR Selection
.br
For reporting commands, display only rows that match \fISelection\fP criteria.
All rows are displayed with the additional "selected" column (\fB-o selected\fP)
showing 1 if the row matches the \fISelection\fP and 0 otherwise. For non-reporting
commands which process LVM entities, the selection can be used to match items
to process. See \fBSelection\fP section in \fBlvmreport\fP(7) man page for more
information about the way the selection criteria are constructed.
.
.HP
.BR \-M | \-\-metadatatype
.IR Type
.br
Specifies which \fItype\fP of on-disk metadata to use, such as \fBlvm1\fP
or \fBlvm2\fP, which can be abbreviated to \fB1\fP or \fB2\fP respectively.
The default (\fBlvm2\fP) can be changed by setting \fBformat\fP
in the \fBglobal\fP section of the config file \fBlvm.conf\fP(5).
.
.HP
.BR \-\-ignorelockingfailure
.br
This lets you proceed with read-only metadata operations such as
\fBlvchange \-ay\fP and \fBvgchange \-ay\fP even if the locking module fails.
One use for this is in a system init script if the lock directory
is mounted read-only when the script runs.
.
.HP
.BR \-\-ignoreskippedcluster
.br
Use to avoid exiting with an non-zero status code if the command is run
without clustered locking and some clustered Volume Groups have to be
skipped over.
.
.HP
.BR \-\-readonly
.br
Run the command in a special read-only mode which will read on-disk
metadata without needing to take any locks. This can be used to peek
inside metadata used by a virtual machine image while the virtual
machine is running.
It can also be used to peek inside the metadata of clustered Volume
Groups when clustered locking is not configured or running. No attempt
will be made to communicate with the device-mapper kernel driver, so
this option is unable to report whether or not Logical Volumes are
actually in use.
.
.HP
.BR \-\-foreign
.br
Cause the command to access foreign VGs, that would otherwise be skipped.
It can be used to report or display a VG that is owned by another host.
This option can cause a command to perform poorly because lvmetad caching
is not used and metadata is read from disks.
.
.HP
.BR \-\-shared
.br
Cause the command to access shared VGs, that would otherwise be skipped
when lvmlockd is not being used. It can be used to report or display a
lockd VG without locking. Applicable only if LVM is compiled with lockd
support.
.
.HP
.BR \-\-addtag
.IR Tag
.br
Add the tag \fITag\fP to a PV, VG or LV.
Supply this argument multiple times to add more than one tag at once.
A tag is a word that can be used to group LVM2 objects of the same type
together.
Tags can be given on the command line in place of PV, VG or LV
arguments. Tags should be prefixed with @ to avoid ambiguity.
Each tag is expanded by replacing it with all objects possessing
that tag which are of the type expected by its position on the command line.
PVs can only possess tags while they are part of a Volume Group:
PV tags are discarded if the PV is removed from the VG.
As an example, you could tag some LVs as \fBdatabase\fP and others
as \fBuserdata\fP and then activate the database ones
with \fBlvchange \-ay @database\fP.
Objects can possess multiple tags simultaneously.
Only the new LVM2 metadata format supports tagging: objects using the
LVM1 metadata format cannot be tagged because the on-disk format does not
support it.
Characters allowed in tags are:
.BR A - Z
.BR a - z
.BR 0 - 9
.BR "_ + . -"
and as of version 2.02.78 the following characters are also accepted:
.BR "/ = ! : # &" .
.
.HP
.BR \-\-deltag
.IR Tag
.br
Delete the tag \fITag\fP from a PV, VG or LV, if it's present.
Supply this argument multiple times to remove more than one tag at once.
.
.HP
.BR \-\-alloc
.RB { anywhere | contiguous | cling | inherit | normal }
.br
Selects the allocation policy when a command needs to allocate
Physical Extents from the Volume Group.
Each Volume Group and Logical Volume has an allocation policy defined.
The default for a Volume Group is \fBnormal\fP which applies
common-sense rules such as not placing parallel stripes on the same
Physical Volume. The default for a Logical Volume is \fBinherit\fP
which applies the same policy as for the Volume Group. These policies can
be changed using \fBlvchange\fP(8) and \fBvgchange\fP(8) or overridden
on the command line of any command that performs allocation.
The \fBcontiguous\fP policy requires that new Physical Extents be placed adjacent
to existing Physical Extents.
The \fBcling\fP policy places new Physical Extents on the same Physical
Volume as existing Physical Extents in the same stripe of the Logical Volume.
If there are sufficient free Physical Extents to satisfy
an allocation request but \fBnormal\fP doesn't use them,
\fBanywhere\fP will - even if that reduces performance by
placing two stripes on the same Physical Volume.
.
.HP
.BR \-\-commandprofile
.IR ProfileName
.br
Selects the command configuration profile to use when processing an LVM command.
See also \fBlvm.conf\fP(5) for more information about \fBcommand profile config\fP and
the way it fits with other LVM configuration methods. Using \fB\-\-commandprofile\fP
option overrides any command profile specified via \fBLVM_COMMAND_PROFILE\fP
environment variable.
.
.HP
.BR \-\-metadataprofile
.IR ProfileName
.br
Selects the metadata configuration profile to use when processing an LVM command.
When using metadata profile during Volume Group or Logical Volume creation,
the metadata profile name is saved in metadata. When such Volume Group or Logical
Volume is processed next time, the metadata profile is automatically applied
and the use of \fB\-\-metadataprofile\fP option is not necessary. See also
\fBlvm.conf\fP(5) for more information about \fBmetadata profile config\fP and the
way it fits with other LVM configuration methods.
.
.HP
.BR \-\-profile
.IR ProfileName
.br
A short form of \fB\-\-metadataprofile\fP for \fBvgcreate\fP, \fBlvcreate\fP,
\fBvgchange\fP and \fBlvchange\fP command and a short form of \fB\-\-commandprofile\fP
for any other command (with the exception of \fBlvmconfig\fP command where the
\fB\-\-profile\fP has special meaning, see \fBlvmconfig\fP(8) for more information).
.
.HP
.BR \-\-reportformat
.IR {basic|json}
.br
Overrides current output format for reports which is defined globally by
\fBreport/output_format\fP configuration setting in \fBlvm.conf\fP(5).
The \fBbasic\fP format is the original format with columns and rows and
if there is more than one report per command, each report is prefixed
with report's name for identification. The \fBjson\fP stands for report
output in JSON format.
.HP
.BR \-\-config
.IR ConfigurationString
.br
Uses the ConfigurationString as direct string representation of the configuration
to override the existing configuration. The ConfigurationString is of exactly
the same format as used in any LVM configuration file. See \fBlvm.conf\fP(5)
for more information about \fBdirect config override on command line\fP and the
way it fits with other LVM configuration methods.
.
.SH VALID NAMES .SH VALID NAMES
. .
The valid characters for VG and LV names are: The valid characters for VG and LV names are:

View File

@@ -16,6 +16,7 @@ from collections import OrderedDict
import dbus import dbus
import os import os
import sys import sys
import time
BUS_NAME = os.getenv('LVM_DBUS_NAME', 'com.redhat.lvmdbus1') BUS_NAME = os.getenv('LVM_DBUS_NAME', 'com.redhat.lvmdbus1')
BASE_INTERFACE = 'com.redhat.lvmdbus1' BASE_INTERFACE = 'com.redhat.lvmdbus1'
@@ -188,10 +189,15 @@ class RemoteInterface(object):
def __init__( def __init__(
self, dbus_object, interface, introspect, self, dbus_object, interface, introspect,
properties=None): properties=None, timelimit=-1):
self.dbus_object = dbus_object self.dbus_object = dbus_object
self.interface = interface self.interface = interface
self.introspect = introspect self.introspect = introspect
self.tmo = 0
if timelimit >= 0:
self.tmo = float(timelimit)
self.tmo *= 1.10
self.dbus_interface = dbus.Interface(self.dbus_object, self.interface) self.dbus_interface = dbus.Interface(self.dbus_object, self.interface)
self._set_props(properties) self._set_props(properties)
@@ -203,7 +209,19 @@ class RemoteInterface(object):
return functools.partial(self, item) return functools.partial(self, item)
def _wrapper(self, _method_name, *args, **kwargs): def _wrapper(self, _method_name, *args, **kwargs):
# Lets see how long a method takes to execute, in call cases we should
# return something when the time limit has been reached.
start = time.time()
result = getattr(self.dbus_interface, _method_name)(*args, **kwargs) result = getattr(self.dbus_interface, _method_name)(*args, **kwargs)
end = time.time()
diff = end - start
if self.tmo > 0.0:
if diff > self.tmo:
std_err_print("\n Time exceeded: %f > %f %s" %
(diff, self.tmo, _method_name))
if self.introspect: if self.introspect:
if 'RETURN_VALUE' in self.introspect[ if 'RETURN_VALUE' in self.introspect[
@@ -236,13 +254,14 @@ class ClientProxy(object):
short_name = ClientProxy._intf_short_name(interface) short_name = ClientProxy._intf_short_name(interface)
self.short_interface_names.append(short_name) self.short_interface_names.append(short_name)
ro = RemoteInterface(self.dbus_object, interface, introspect, ro = RemoteInterface(self.dbus_object, interface, introspect,
properties) properties, timelimit=self.tmo)
setattr(self, short_name, ro) setattr(self, short_name, ro)
def __init__(self, bus, object_path, interface_prop_hash=None, def __init__(self, bus, object_path, interface_prop_hash=None,
interfaces=None): interfaces=None, timelimit=-1):
self.object_path = object_path self.object_path = object_path
self.short_interface_names = [] self.short_interface_names = []
self.tmo = timelimit
self.dbus_object = bus.get_object( self.dbus_object = bus.get_object(
BUS_NAME, self.object_path, introspect=False) BUS_NAME, self.object_path, introspect=False)

View File

@@ -1491,6 +1491,27 @@ wait_pvmove_lv_ready() {
fi fi
} }
# Holds device open with sleep which automatically expires after given timeout
# Prints PID of running holding sleep process in background
hold_device_open() {
local vgname=$1
local lvname=$2
local sec=${3:-20} # default 20sec
sleep $sec < "$DM_DEV_DIR/$vgname/$lvname" >/dev/null 2>&1 &
SLEEP_PID=$!
# wait till device is openned
for i in $(seq 1 50) ; do
if test "$(dmsetup info --noheadings -c -o open $vgname-$lvname)" -ne 0 ; then
echo "$SLEEP_PID"
return
fi
sleep .1
done
die "$vgname-$lvname expected to be openned, but it's not!"
}
# return total memory size in kB units # return total memory size in kB units
total_mem() { total_mem() {
while IFS=":" read -r a b ; do while IFS=":" read -r a b ; do

View File

@@ -0,0 +1,69 @@
#!/bin/sh
# Copyright (C) 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, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
SKIP_WITH_LVMLOCKD=1
SKIP_WITH_LVMPOLLD=1
. lib/inittest
aux have_raid 1 10 1 || skip
aux prepare_vg 6
#
# FIXME: add multi-segment leg tests
#
function _check_raid
{
local vg=$1
shift
local lv=$1
shift
local fail=$1
shift
local good=$1
shift
local devs=$*
aux wait_for_sync $vg $lv
aux disable_dev --error --silent $devs
mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
fsck.ext4 -fn "$DM_DEV_DIR/$vg/$lv"
check raid_leg_status $vg $lv "$fail"
aux enable_dev --silent $devs
lvs -a -o +devices $vg | tee out
not grep unknown out
lvchange --refresh $vg/$lv
fsck.ext4 -fn "$DM_DEV_DIR/$vg/$lv"
aux wait_for_sync $vg $lv
fsck.ext4 -fn "$DM_DEV_DIR/$vg/$lv"
check raid_leg_status $vg $lv "$good"
}
# raid1 with transiently failing devices
lv=4way
lvcreate -aey --type raid1 -m 3 --ignoremonitoring -L 1 -n $lv $vg
_check_raid $vg $lv "ADAD" "AAAA" $dev2 $dev4
lvremove -y $vg/$lv
# raid6 with transiently failing devices
lv=6way
lvcreate -aey --type raid6 -i 4 --ignoremonitoring -L 1 -n $lv $vg
_check_raid $vg $lv "ADADAA" "AAAAAA" $dev2 $dev4
lvremove -y $vg/$lv
# raid10 with transiently failing devices
lv=6way
lvcreate -aey --type raid10 -i 3 -m 1 --ignoremonitoring -L 1 -n $lv $vg
_check_raid $vg $lv "ADADDA" "AAAAAA" $dev2 $dev4 $dev5
lvremove -y $vg/$lv
vgremove -f $vg

View File

@@ -32,7 +32,8 @@ get_image_pvs() {
aux have_raid 1 3 0 || skip aux have_raid 1 3 0 || skip
aux prepare_pvs 9 aux prepare_pvs 9
vgcreate -s 256k $vg $(cat DEVICES) # vgcreate -s 256k $vg $(cat DEVICES)
vgcreate -s 2m $vg $(cat DEVICES)
########################################### ###########################################
# RAID1 convert tests # RAID1 convert tests
@@ -135,15 +136,27 @@ lvconvert --yes --splitmirrors 1 --name $lv2 $vg/$lv1 "$dev2"
lvremove -ff $vg lvremove -ff $vg
########################################### ###########################################
# RAID1 split + trackchanges / merge # RAID1 split + trackchanges / merge with content check
########################################### ###########################################
# 3-way to 2-way/linear # 3-way to 2-way/linear
lvcreate --type raid1 -m 2 -l 2 -n $lv1 $vg lvcreate --type raid1 -m 2 -l 1 -n $lv1 $vg
mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
fsck.ext4 -fn "$DM_DEV_DIR/$vg/$lv1"
aux wait_for_sync $vg $lv1 aux wait_for_sync $vg $lv1
fsck.ext4 -fn "$DM_DEV_DIR/$vg/$lv1"
lvconvert --splitmirrors 1 --trackchanges $vg/$lv1 lvconvert --splitmirrors 1 --trackchanges $vg/$lv1
check lv_exists $vg $lv1 check lv_exists $vg $lv1
check linear $vg ${lv1}_rimage_2 check linear $vg ${lv1}_rimage_2
fsck.ext4 -fn "$DM_DEV_DIR/mapper/$vg-${lv1}_rimage_2"
dd of="$DM_DEV_DIR/$vg/$lv1" if=/dev/zero bs=512 oflag=direct count=`blockdev --getsz "$DM_DEV_DIR/$vg/$lv1"`
not fsck.ext4 -fn "$DM_DEV_DIR/$vg/$lv1"
fsck.ext4 -fn "$DM_DEV_DIR/mapper/$vg-${lv1}_rimage_2"
# FIXME: needed on tiny loop but not on real block backend ?
lvchange --refresh $vg/$lv1
lvconvert --merge $vg/${lv1}_rimage_2 lvconvert --merge $vg/${lv1}_rimage_2
aux wait_for_sync $vg $lv1
lvconvert --splitmirrors 1 --trackchanges $vg/$lv1
not fsck.ext4 -fn "$DM_DEV_DIR/mapper/$vg-${lv1}_rimage_2"
# FIXME: ensure no residual devices # FIXME: ensure no residual devices
lvremove -ff $vg lvremove -ff $vg

View File

@@ -50,6 +50,12 @@ not lvconvert --thin --thinpool $vg/tpool $vg/$lv1
# Switch to 'writethrough' - this should be supported # Switch to 'writethrough' - this should be supported
lvchange --cachemode writethrough $vg/$lv1 lvchange --cachemode writethrough $vg/$lv1
# FIXME
# systemd on fc23 'strikes-in' and unmounts mnt
# ATM the reason is unclear (bug in systemd, bad udev rules?)
# as a workaround mount again and 'WARN' test
should not mount "$DM_DEV_DIR/$vg/$lv1" mnt
lvconvert --thin $vg/$lv1 --originname extorg --thinpool $vg/tpool lvconvert --thin $vg/$lv1 --originname extorg --thinpool $vg/tpool
# check cache exist as extorg-real # check cache exist as extorg-real

View File

@@ -29,9 +29,7 @@ snap_and_merge() {
sync sync
lvs -a $vg lvs -a $vg
# keep device open to prevent instant merge SLEEP_PID=$(aux hold_device_open $vg $lv1 20)
sleep 20 < "$DM_DEV_DIR/$vg/$lv1" &
SLEEP_PID=$!
# initiate background merge # initiate background merge
lvconvert -b --mergesnapshot $vg/$lv2 lvconvert -b --mergesnapshot $vg/$lv2

View File

@@ -24,16 +24,6 @@ fill() {
die "Snapshot does not fit $1" die "Snapshot does not fit $1"
} }
# Wait until device is opened
wait_for_open_() {
for i in $(seq 1 50) ; do
test $(dmsetup info --noheadings -c -o open $1) -ne 0 && return
sleep 0.1
done
die "$1 expected to be openned, but it's not!"
}
cleanup_tail() cleanup_tail()
{ {
test -z "$SLEEP_PID" || kill $SLEEP_PID || true test -z "$SLEEP_PID" || kill $SLEEP_PID || true
@@ -125,10 +115,7 @@ lvchange -ay $vg1
check lv_field $vg1/$lv1 lv_active "$CHECK_ACTIVE" check lv_field $vg1/$lv1 lv_active "$CHECK_ACTIVE"
# Test removal of opened (but unmounted) snapshot (device busy) for a while # Test removal of opened (but unmounted) snapshot (device busy) for a while
sleep 120 < "$DM_DEV_DIR/$vg1/$lv1" & SLEEP_PID=$(aux hold_device_open $vg1 $lv1 60)
SLEEP_PID=$!
wait_for_open_ "$vg1-$lv1"
# Opened virtual snapshot device is not removable # Opened virtual snapshot device is not removable
# it should retry device removal for a few seconds # it should retry device removal for a few seconds

View File

@@ -72,18 +72,18 @@ touch "$mntusedir/file$$"
sync sync
# Running 'keeper' process sleep holds the block device still in use # Running 'keeper' process sleep holds the block device still in use
sleep 60 < "$mntusedir/file$$" & sleep 60 < "$mntusedir/file$$" >/dev/null 2>&1 &
PID_SLEEP=$! PID_SLEEP=$!
lvs -a $vg lvs -a $vg
# Fill pool above 95% (to cause 'forced lazy umount) # Fill pool above 95% (to cause 'forced lazy umount)
dd if=/dev/zero of="$mntdir/file$$" bs=256K count=20 conv=fdatasync dd if=/dev/zero of="$mntdir/file$$" bs=256K count=20 conv=fdatasync
sync
lvs -a $vg lvs -a $vg
# Could loop here for a few secs so dmeventd can do some work # Could loop here for a few secs so dmeventd can do some work
# In the worst case check only happens every 10 seconds :( # In the worst case check only happens every 10 seconds :(
# With low water mark it should react way faster # With low water mark it quickly discovers overflow and umounts $vg/$lv1
for i in $(seq 1 12) ; do for i in $(seq 1 12) ; do
is_lv_opened_ "$vg/$lv1" || break is_lv_opened_ "$vg/$lv1" || break
test $i -lt 12 || die "$mntdir should have been unmounted by dmeventd!" test $i -lt 12 || die "$mntdir should have been unmounted by dmeventd!"

View File

@@ -1,5 +1,5 @@
#!/bin/sh #!/bin/sh
# Copyright (C) 2014 Red Hat, Inc. All rights reserved. # Copyright (C) 2014-2016 Red Hat, Inc. All rights reserved.
# #
# This copyrighted material is made available to anyone wishing to use, # This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions # modify, copy, or redistribute it subject to the terms and conditions
@@ -37,15 +37,24 @@ check lv_field $vg/snap thin_id "3"
lvconvert --mergethin $vg/snap lvconvert --mergethin $vg/snap
umount mnt umount mnt
check lv_field $vg/$lv1 thin_id "1"
check lv_field $vg/pool transaction_id "3"
vgchange -an $vg vgchange -an $vg
# Check reboot case # Check reboot case
vgchange -ay --sysinit $vg vgchange -ay --sysinit $vg
# Metadata are still not updated (--poll n)
check lv_field $vg/$lv1 thin_id "1" # Check correct thin_id is shown after activation
# even when metadata were not yet physically modified.
# Merge take its place during activation,
# but pool transaction_id still needs metadata update.
check lv_field $vg/$lv1 thin_id "3"
check lv_field $vg/pool transaction_id "3" check lv_field $vg/pool transaction_id "3"
# Check the metadata are updated after refresh # Check the metadata are updated after refresh
#
vgchange --refresh $vg vgchange --refresh $vg
check lv_field $vg/$lv1 thin_id "3" check lv_field $vg/$lv1 thin_id "3"
check lv_field $vg/pool transaction_id "4" check lv_field $vg/pool transaction_id "4"

View File

@@ -53,6 +53,13 @@ not vgchange -p 2 $vg 2>err
grep "MaxPhysicalVolumes is less than the current number $pv_count of PVs for" err grep "MaxPhysicalVolumes is less than the current number $pv_count of PVs for" err
check vg_field $vg max_pv 128 check vg_field $vg max_pv 128
# try some numbers around MAX limit (uint32)
vgchange -p 4294967295 $vg
invalid vgchange -p 4294967296 $vg
invalid vgchange -p 18446744073709551615 $vg
invalid vgchange -p 18446744073709551616 $vg
check vg_field $vg max_pv 4294967295
# vgchange -l MaxLogicalVolumes # vgchange -l MaxLogicalVolumes
check vg_field $vg max_lv 0 check vg_field $vg max_lv 0
invalid vgchange -l -128 $vg invalid vgchange -l -128 $vg

View File

@@ -1,3 +1,4 @@
# #
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. # Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
@@ -140,6 +141,8 @@ all: device-mapper
CFLAGS_lvm.o += $(EXTRA_EXEC_CFLAGS) CFLAGS_lvm.o += $(EXTRA_EXEC_CFLAGS)
CFLAGS_lvmcmdline.o += $(VALGRIND_CFLAGS) CFLAGS_lvmcmdline.o += $(VALGRIND_CFLAGS)
INCLUDES += -I$(top_builddir)/tools
lvm: $(OBJECTS) lvm.o $(top_builddir)/lib/liblvm-internal.a lvm: $(OBJECTS) lvm.o $(top_builddir)/lib/liblvm-internal.a
$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) -o $@ $(OBJECTS) lvm.o \ $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) -o $@ $(OBJECTS) lvm.o \
$(LVMLIBS) $(READLINE_LIBS) $(LIBS) -rdynamic $(LVMLIBS) $(READLINE_LIBS) $(LIBS) -rdynamic
@@ -173,12 +176,35 @@ liblvm2cmd.$(LIB_SUFFIX).$(LIB_VERSION): liblvm2cmd.$(LIB_SUFFIX)
$(CC) -E -P $(srcdir)/cmdnames.h 2> /dev/null | \ $(CC) -E -P $(srcdir)/cmdnames.h 2> /dev/null | \
egrep -v '^ *(|#.*|config|devtypes|dumpconfig|formats|fullreport|help|lastlog|lvpoll|pvdata|segtypes|systemid|tags|version) *$$' > .commands egrep -v '^ *(|#.*|config|devtypes|dumpconfig|formats|fullreport|help|lastlog|lvpoll|pvdata|segtypes|systemid|tags|version) *$$' > .commands
ccmd: create-commands.c ccmd: $(srcdir)/create-commands.c
$(CC) create-commands.c -o ccmd $(CC) $(srcdir)/create-commands.c -o ccmd
command-lines.h: ccmd .DELETE_ON_ERROR:
./ccmd --output struct command-lines.in > command-lines.h
./ccmd --output count command-lines.in > command-lines-count.h command-lines.h: $(srcdir)/command-lines.in ccmd
$(top_builddir)/tools/ccmd --output struct $(srcdir)/command-lines.in > $@
command-lines-count.h: $(srcdir)/command-lines.in ccmd
$(top_builddir)/tools/ccmd --output count $(srcdir)/command-lines.in > $@
# move properly to configure
WC = /usr/bin/wc
GREP = /bin/grep
SORT = /bin/sort
CUT = /bin/cut
SED = /bin/sed
# FIXME Add licence text from template file
command-lines-count-new.h: $(srcdir)/command-lines.in ccmd Makefile
set -o pipefail && \
(echo -n "#define COMMAND_COUNT " && \
$(GREP) '^ID:' $(srcdir)/command-lines.in | $(WC) -l && \
echo -e "enum {\n\tno_CMD," && \
$(GREP) '^ID:' $(srcdir)/command-lines.in | $(CUT) -d\ -f2 | $(SORT) -u | $(SED) 's/\(.*\)/\t&_CMD,/' && \
echo -e "\tCOMMAND_ID_COUNT,\n};" \
) > $@
$(SOURCES:%.c=%.d): command-lines.h command-lines-count.h
ifneq ("$(CFLOW_CMD)", "") ifneq ("$(CFLOW_CMD)", "")
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES)) CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))

File diff suppressed because it is too large Load Diff

View File

@@ -264,7 +264,7 @@ RULE: --alloc --discards --zero --cachemode --cachepolicy --cachesettings not lv
# like above, it was previouly allowed in combination. # like above, it was previouly allowed in combination.
lvchange --resync VG|LV_raid_mirror|Tag|Select ... lvchange --resync VG|LV_raid_mirror|Tag|Select ...
OO: --activate Activate, OO_LVCHANGE OO: --activate Active, OO_LVCHANGE
ID: lvchange_resync ID: lvchange_resync
DESC: Resyncronize a mirror or raid LV. DESC: Resyncronize a mirror or raid LV.
RULE: all not lv_is_pvmove lv_is_locked RULE: all not lv_is_pvmove lv_is_locked
@@ -517,6 +517,15 @@ FLAGS: SECONDARY_SYNTAX
--- ---
lvconvert --mergethin LV_thin ...
OO: OO_LVCONVERT
ID: lvconvert_merge_thin
DESC: Merge thin LV into its origin LV.
RULE: all not lv_is_locked lv_is_pvmove lv_is_merging_origin lv_is_virtual_origin lv_is_external_origin lv_is_merging_cow
RULE: all and lv_is_visible
---
# lvconvert snapshot-related utilities # lvconvert snapshot-related utilities
# Create a new command set for these and migrate them out of lvconvert? # Create a new command set for these and migrate them out of lvconvert?
@@ -632,12 +641,7 @@ OO_LVCREATE_CACHE: --cachemode CacheMode, --cachepolicy String, --cachesettings
OO_LVCREATE_POOL: --poolmetadatasize SizeMB, --poolmetadataspare Bool, --chunksize SizeKB OO_LVCREATE_POOL: --poolmetadatasize SizeMB, --poolmetadataspare Bool, --chunksize SizeKB
# FIXME: it's silly to include --mirrors 0 here. Fix the tests to not use OO_LVCREATE_THIN: --discards Discards, --errorwhenfull Bool
# --mirrors 0 in commands that do not accept any non-zero --mirrors
# option, and then remove this. Accepting an option, only so that the
# option's value can invalidate the use of the option is not advisable.
OO_LVCREATE_THIN: --discards Discards, --errorwhenfull Bool, --mirrors 0
OO_LVCREATE_RAID: --mirrors SNumber, --stripes Number, --stripesize SizeKB, OO_LVCREATE_RAID: --mirrors SNumber, --stripes Number, --stripesize SizeKB,
--regionsize SizeMB, --minrecoveryrate SizeKB, --maxrecoveryrate SizeKB --regionsize SizeMB, --minrecoveryrate SizeKB, --maxrecoveryrate SizeKB
@@ -660,15 +664,10 @@ FLAGS: SECONDARY_SYNTAX
--- ---
# FIXME: consider removing the --mirrors 0, --stripes 1 options
# and just reporting an error (or ignoring) if mirrors or stripes
# options are given. Same reasoning as above: it's confusing to
# advertise an option when the only value accepted for the option
# makes the option do nothing.
lvcreate --type linear --size SizeMB VG lvcreate --type linear --size SizeMB VG
OO: --mirrors 0, --stripes 1, OO_LVCREATE OO: OO_LVCREATE
OP: PV ... OP: PV ...
IO: --mirrors 0, --stripes 1
ID: lvcreate_linear ID: lvcreate_linear
DESC: Create a linear LV. DESC: Create a linear LV.
FLAGS: SECONDARY_SYNTAX FLAGS: SECONDARY_SYNTAX
@@ -678,8 +677,9 @@ FLAGS: SECONDARY_SYNTAX
# to people to not see the name parameter. # to people to not see the name parameter.
lvcreate --size SizeMB VG lvcreate --size SizeMB VG
OO: --type linear, --mirrors 0, --stripes 1, OO_LVCREATE OO: --type linear, OO_LVCREATE
OP: PV ... OP: PV ...
IO: --mirrors 0, --stripes 1
ID: lvcreate_linear ID: lvcreate_linear
DESC: Create a linear LV (default --type linear). DESC: Create a linear LV (default --type linear).
DESC: When --name is omitted, the name is generated. DESC: When --name is omitted, the name is generated.
@@ -769,6 +769,7 @@ lvcreate --type thin-pool --size SizeMB VG
OO: --thinpool LV_new, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE, OO: --thinpool LV_new, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
--stripes Number, --stripesize SizeKB --stripes Number, --stripesize SizeKB
OP: PV ... OP: PV ...
IO: --mirrors 0
ID: lvcreate_thinpool ID: lvcreate_thinpool
DESC: Create a thin pool. DESC: Create a thin pool.
@@ -777,6 +778,7 @@ lvcreate --thin --size SizeMB VG
OO: --type thin-pool, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE, OO: --type thin-pool, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
--stripes Number, --stripesize SizeKB --stripes Number, --stripesize SizeKB
OP: PV ... OP: PV ...
IO: --mirrors 0
ID: lvcreate_thinpool ID: lvcreate_thinpool
DESC: Create a thin pool (variant, infers --type thin-pool). DESC: Create a thin pool (variant, infers --type thin-pool).
FLAGS: SECONDARY_SYNTAX FLAGS: SECONDARY_SYNTAX
@@ -786,6 +788,7 @@ lvcreate --size SizeMB --thinpool LV_new VG
OO: --thin, --type thin-pool, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE, OO: --thin, --type thin-pool, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
--stripes Number, --stripesize SizeKB --stripes Number, --stripesize SizeKB
OP: PV ... OP: PV ...
IO: --mirrors 0
ID: lvcreate_thinpool ID: lvcreate_thinpool
DESC: Create a thin pool named by the --thinpool arg DESC: Create a thin pool named by the --thinpool arg
DESC: (variant, infers --type thin-pool). DESC: (variant, infers --type thin-pool).
@@ -817,12 +820,14 @@ FLAGS: SECONDARY_SYNTAX
lvcreate --type thin --virtualsize SizeMB --thinpool LV_thinpool VG lvcreate --type thin --virtualsize SizeMB --thinpool LV_thinpool VG
OO: --thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE OO: --thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE
IO: --mirrors 0
ID: lvcreate_thin_vol ID: lvcreate_thin_vol
DESC: Create a thin LV in a thin pool. DESC: Create a thin LV in a thin pool.
# alternate form of lvcreate --type thin # alternate form of lvcreate --type thin
lvcreate --type thin --virtualsize SizeMB LV_thinpool lvcreate --type thin --virtualsize SizeMB LV_thinpool
OO: --thin, OO_LVCREATE_THIN, OO_LVCREATE OO: --thin, OO_LVCREATE_THIN, OO_LVCREATE
IO: --mirrors 0
ID: lvcreate_thin_vol ID: lvcreate_thin_vol
DESC: Create a thin LV in a thin pool named in the first arg DESC: Create a thin LV in a thin pool named in the first arg
DESC: (variant, also see --thinpool for naming pool). DESC: (variant, also see --thinpool for naming pool).
@@ -834,6 +839,7 @@ FLAGS: SECONDARY_SYNTAX
# alternate form of lvcreate --type thin # alternate form of lvcreate --type thin
lvcreate --virtualsize SizeMB --thinpool LV_thinpool VG lvcreate --virtualsize SizeMB --thinpool LV_thinpool VG
OO: --type thin, --thin, OO_LVCREATE_THIN, OO_LVCREATE OO: --type thin, --thin, OO_LVCREATE_THIN, OO_LVCREATE
IO: --mirrors 0
ID: lvcreate_thin_vol ID: lvcreate_thin_vol
DESC: Create a thin LV in a thin pool (variant, infers --type thin). DESC: Create a thin LV in a thin pool (variant, infers --type thin).
FLAGS: SECONDARY_SYNTAX FLAGS: SECONDARY_SYNTAX
@@ -841,6 +847,7 @@ FLAGS: SECONDARY_SYNTAX
# alternate form of lvcreate --type thin # alternate form of lvcreate --type thin
lvcreate --virtualsize SizeMB LV_thinpool lvcreate --virtualsize SizeMB LV_thinpool
OO: --type thin, --thin, OO_LVCREATE_THIN, OO_LVCREATE OO: --type thin, --thin, OO_LVCREATE_THIN, OO_LVCREATE
IO: --mirrors 0
ID: lvcreate_thin_vol ID: lvcreate_thin_vol
DESC: Create a thin LV in the thin pool named in the first arg DESC: Create a thin LV in the thin pool named in the first arg
DESC: (variant, infers --type thin, also see --thinpool for DESC: (variant, infers --type thin, also see --thinpool for
@@ -851,12 +858,14 @@ FLAGS: SECONDARY_SYNTAX
lvcreate --type thin LV_thin lvcreate --type thin LV_thin
OO: --thin, OO_LVCREATE_THIN, OO_LVCREATE OO: --thin, OO_LVCREATE_THIN, OO_LVCREATE
IO: --mirrors 0
ID: lvcreate_thin_snapshot ID: lvcreate_thin_snapshot
DESC: Create a thin LV that is a snapshot of an existing thin LV. DESC: Create a thin LV that is a snapshot of an existing thin LV.
# alternate form of lvcreate --type thin # alternate form of lvcreate --type thin
lvcreate --thin LV_thin lvcreate --thin LV_thin
OO: --type thin, OO_LVCREATE_THIN, OO_LVCREATE OO: --type thin, OO_LVCREATE_THIN, OO_LVCREATE
IO: --mirrors 0
ID: lvcreate_thin_snapshot ID: lvcreate_thin_snapshot
DESC: Create a thin LV that is a snapshot of an existing thin LV DESC: Create a thin LV that is a snapshot of an existing thin LV
DESC: (infers --type thin). DESC: (infers --type thin).
@@ -865,33 +874,27 @@ FLAGS: SECONDARY_SYNTAX
# alternate form of lvcreate --type thin # alternate form of lvcreate --type thin
lvcreate --snapshot LV_thin lvcreate --snapshot LV_thin
OO: --type thin, OO_LVCREATE_THIN, OO_LVCREATE OO: --type thin, OO_LVCREATE_THIN, OO_LVCREATE
IO: --mirrors 0
ID: lvcreate_thin_snapshot ID: lvcreate_thin_snapshot
DESC: Create a thin LV that is a snapshot of an existing thin LV DESC: Create a thin LV that is a snapshot of an existing thin LV
DESC: (infers --type thin). DESC: (infers --type thin).
lvcreate --type thin --thinpool LV_thinpool LV lvcreate --type thin --thinpool LV_thinpool LV
OO: --thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE OO: --thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE
IO: --mirrors 0
ID: lvcreate_thin_snapshot_of_external ID: lvcreate_thin_snapshot_of_external
DESC: Create a thin LV that is a snapshot of an external origin LV. DESC: Create a thin LV that is a snapshot of an external origin LV.
# alternate form of lvcreate --type thin --thinpool LV_thinpool LV # alternate form of lvcreate --type thin --thinpool LV_thinpool LV
lvcreate --snapshot --thinpool LV_thinpool LV lvcreate --snapshot --thinpool LV_thinpool LV
OO: --type thin, OO_LVCREATE_THIN, OO_LVCREATE OO: --type thin, OO_LVCREATE_THIN, OO_LVCREATE
IO: --mirrors 0
ID: lvcreate_thin_snapshot_of_external ID: lvcreate_thin_snapshot_of_external
DESC: Create a thin LV that is a snapshot of an external origin LV DESC: Create a thin LV that is a snapshot of an external origin LV
DESC: (infers --type thin). DESC: (infers --type thin).
--- ---
lvconvert --mergethin LV_thin ...
OO: OO_LVCONVERT
ID: lvconvert_merge_thin
DESC: Merge thin LV into its origin LV.
RULE: all not lv_is_locked lv_is_pvmove lv_is_merging_origin lv_is_virtual_origin lv_is_external_origin lv_is_merging_cow
RULE: all and lv_is_visible
---
# stripes option is not intuitive when creating a thin LV, # stripes option is not intuitive when creating a thin LV,
# but here it applies to creating the new thin pool that # but here it applies to creating the new thin pool that
# is used for the thin LV # is used for the thin LV
@@ -912,6 +915,7 @@ lvcreate --type thin --virtualsize SizeMB --size SizeMB --thinpool LV_new
OO: --thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE, OO: --thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
--stripes Number, --stripesize SizeKB --stripes Number, --stripesize SizeKB
OP: PV ... OP: PV ...
IO: --mirrors 0
ID: lvcreate_thin_vol_and_thinpool ID: lvcreate_thin_vol_and_thinpool
DESC: Create a thin LV, first creating a thin pool for it, DESC: Create a thin LV, first creating a thin pool for it,
DESC: where the new thin pool is named by the --thinpool arg. DESC: where the new thin pool is named by the --thinpool arg.
@@ -921,6 +925,7 @@ lvcreate --thin --virtualsize SizeMB --size SizeMB --thinpool LV_new
OO: --type thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE, OO: --type thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
--stripes Number, --stripesize SizeKB --stripes Number, --stripesize SizeKB
OP: PV ... OP: PV ...
IO: --mirrors 0
ID: lvcreate_thin_vol_and_thinpool ID: lvcreate_thin_vol_and_thinpool
DESC: Create a thin LV, first creating a thin pool for it, DESC: Create a thin LV, first creating a thin pool for it,
DESC: where the new thin pool is named by the --thinpool arg DESC: where the new thin pool is named by the --thinpool arg
@@ -932,6 +937,7 @@ lvcreate --type thin --virtualsize SizeMB --size SizeMB LV_new|VG
OO: --thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE, OO: --thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
--stripes Number, --stripesize SizeKB --stripes Number, --stripesize SizeKB
OP: PV ... OP: PV ...
IO: --mirrors 0
ID: lvcreate_thin_vol_and_thinpool ID: lvcreate_thin_vol_and_thinpool
DESC: Create a thin LV, first creating a thin pool for it, DESC: Create a thin LV, first creating a thin pool for it,
DESC: where the new thin pool is named in the first arg, DESC: where the new thin pool is named in the first arg,
@@ -944,6 +950,7 @@ lvcreate --thin --virtualsize SizeMB --size SizeMB LV_new|VG
OO: --type thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE, OO: --type thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
--stripes Number, --stripesize SizeKB --stripes Number, --stripesize SizeKB
OP: PV ... OP: PV ...
IO: --mirrors 0
ID: lvcreate_thin_vol_and_thinpool ID: lvcreate_thin_vol_and_thinpool
DESC: Create a thin LV, first creating a thin pool for it, DESC: Create a thin LV, first creating a thin pool for it,
DESC: where the new thin pool is named in the first arg, DESC: where the new thin pool is named in the first arg,
@@ -957,6 +964,7 @@ lvcreate --size SizeMB --virtualsize SizeMB VG
OO: --type thin, --type snapshot, --thin, --snapshot, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE, OO: --type thin, --type snapshot, --thin, --snapshot, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
--stripes Number, --stripesize SizeKB --stripes Number, --stripesize SizeKB
OP: PV ... OP: PV ...
IO: --mirrors 0
ID: lvcreate_thin_vol_with_thinpool_or_sparse_snapshot ID: lvcreate_thin_vol_with_thinpool_or_sparse_snapshot
DESC: Create a thin LV, first creating a thin pool for it DESC: Create a thin LV, first creating a thin pool for it
DESC: (infers --type thin). DESC: (infers --type thin).
@@ -1327,7 +1335,7 @@ OO_VGCHANGE: --autobackup Bool, --ignoremonitoring, --ignoreskippedcluster,
# because it can function as a required opt. # because it can function as a required opt.
OO_VGCHANGE_META: --addtag Tag, --deltag Tag, OO_VGCHANGE_META: --addtag Tag, --deltag Tag,
--logicalvolume Number, --maxphysicalvolumes Number, --alloc Alloc, --uuid, --logicalvolume Number, --maxphysicalvolumes Uint32, --alloc Alloc, --uuid,
--clustered Bool, --pvmetadatacopies MetadataCopiesPV, --vgmetadatacopies MetadataCopiesVG, --clustered Bool, --pvmetadatacopies MetadataCopiesPV, --vgmetadatacopies MetadataCopiesVG,
--physicalextentsize SizeMB, --resizeable Bool, --systemid String, --locktype LockType, --physicalextentsize SizeMB, --resizeable Bool, --systemid String, --locktype LockType,
--profile String, --detachprofile, --metadataprofile String --profile String, --detachprofile, --metadataprofile String
@@ -1394,7 +1402,7 @@ ID: vgconvert_general
vgcreate VG_new PV ... vgcreate VG_new PV ...
OO: --addtag Tag, --alloc Alloc, --autobackup Bool, --clustered Bool, --maxlogicalvolumes Number, OO: --addtag Tag, --alloc Alloc, --autobackup Bool, --clustered Bool, --maxlogicalvolumes Number,
--maxphysicalvolumes Number, --metadataprofile String, --metadatatype MetadataType, --maxphysicalvolumes Uint32, --metadataprofile String, --metadatatype MetadataType,
--physicalextentsize SizeMB, --force, --zero Bool, --labelsector Number, --physicalextentsize SizeMB, --force, --zero Bool, --labelsector Number,
--metadatasize SizeMB, --pvmetadatacopies MetadataCopiesPV, --vgmetadatacopies MetadataCopiesVG, --metadatasize SizeMB, --pvmetadatacopies MetadataCopiesPV, --vgmetadatacopies MetadataCopiesVG,
--reportformat ReportFmt, --dataalignment SizeKB, --dataalignmentoffset SizeKB, --reportformat ReportFmt, --dataalignment SizeKB, --dataalignmentoffset SizeKB,
@@ -1527,7 +1535,7 @@ OO_VGSPLIT: --autobackup Bool
# used only when the destination VG is new # used only when the destination VG is new
OO_VGSPLIT_NEW: --alloc Alloc, --clustered Bool, OO_VGSPLIT_NEW: --alloc Alloc, --clustered Bool,
--maxlogicalvolumes Number, --maxphysicalvolumes Number, --maxlogicalvolumes Number, --maxphysicalvolumes Uint32,
--metadatatype MetadataType, --vgmetadatacopies MetadataCopiesVG --metadatatype MetadataType, --vgmetadatacopies MetadataCopiesVG
vgsplit VG VG PV ... vgsplit VG VG PV ...
@@ -1581,6 +1589,7 @@ formats
ID: formats_general ID: formats_general
help help
OP: String ...
ID: help_general ID: help_general
version version

View File

@@ -51,8 +51,9 @@ struct command_name {
*/ */
/* arg_def flags */ /* arg_def flags */
#define ARG_DEF_FLAG_NEW 1 << 0 #define ARG_DEF_FLAG_NEW_VG 1 << 0
#define ARG_DEF_FLAG_MAY_REPEAT 1 << 1 #define ARG_DEF_FLAG_NEW_LV 1 << 1
#define ARG_DEF_FLAG_MAY_REPEAT 1 << 2
static inline int val_bit_is_set(uint64_t val_bits, int val_enum) static inline int val_bit_is_set(uint64_t val_bits, int val_enum)
{ {
@@ -144,6 +145,7 @@ struct cmd_rule {
#define CMD_OO_ARGS 150 /* optional opt args */ #define CMD_OO_ARGS 150 /* optional opt args */
#define CMD_RP_ARGS 8 /* required positional args */ #define CMD_RP_ARGS 8 /* required positional args */
#define CMD_OP_ARGS 8 /* optional positional args */ #define CMD_OP_ARGS 8 /* optional positional args */
#define CMD_IO_ARGS 8 /* ignore opt args */
#define CMD_MAX_RULES 32 /* max number of rules per command def */ #define CMD_MAX_RULES 32 /* max number of rules per command def */
/* /*
@@ -185,12 +187,16 @@ struct command {
/* optional positional args */ /* optional positional args */
struct pos_arg optional_pos_args[CMD_OP_ARGS]; struct pos_arg optional_pos_args[CMD_OP_ARGS];
/* unused opt args, are ignored instead of causing an error */
struct opt_arg ignore_opt_args[CMD_IO_ARGS];
struct cmd_rule rules[CMD_MAX_RULES]; struct cmd_rule rules[CMD_MAX_RULES];
int ro_count; int ro_count;
int oo_count; int oo_count;
int rp_count; int rp_count;
int op_count; int op_count;
int io_count;
/* used for processing current position */ /* used for processing current position */
int pos_count; int pos_count;

View File

@@ -34,6 +34,7 @@ int size_kb_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int size_mb_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; } int size_mb_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int size_mb_arg_with_percent(struct cmd_context *cmd, struct arg_values *av) { return 0; } int size_mb_arg_with_percent(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int int_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; } int int_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int uint32_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int int_arg_with_sign(struct cmd_context *cmd, struct arg_values *av) { return 0; } int int_arg_with_sign(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int int_arg_with_sign_and_percent(struct cmd_context *cmd, struct arg_values *av) { return 0; } int int_arg_with_sign_and_percent(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int major_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; } int major_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
@@ -67,6 +68,7 @@ struct opt_name {
int val_enum; /* xyz_VAL when --foo takes a val like "--foo xyz" */ int val_enum; /* xyz_VAL when --foo takes a val like "--foo xyz" */
uint32_t unused1; uint32_t unused1;
uint32_t unused2; uint32_t unused2;
const char *desc;
}; };
/* also see val_props in tools.h and vals.h */ /* also see val_props in tools.h and vals.h */
@@ -103,7 +105,7 @@ enum {
/* create foo_ARG enums for --option's */ /* create foo_ARG enums for --option's */
enum { enum {
#define arg(a, b, c, d, e, f) a , #define arg(a, b, c, d, e, f, g) a ,
#include "args.h" #include "args.h"
#undef arg #undef arg
}; };
@@ -135,7 +137,7 @@ static struct val_name val_names[VAL_COUNT + 1] = {
/* create table of option names, e.g. --foo, and corresponding enum from args.h */ /* create table of option names, e.g. --foo, and corresponding enum from args.h */
static struct opt_name opt_names[ARG_COUNT + 1] = { static struct opt_name opt_names[ARG_COUNT + 1] = {
#define arg(a, b, c, d, e, f) { # a, a, b, "", "--" c, d, e, f }, #define arg(a, b, c, d, e, f, g) { # a, a, b, "", "--" c, d, e, f, g },
#include "args.h" #include "args.h"
#undef arg #undef arg
}; };
@@ -179,11 +181,18 @@ static struct cmd_name cmd_names[MAX_CMD_NAMES] = {
#undef xx #undef xx
}; };
/* array of pointers into opt_names[] that is sorted alphabetically (by long opt name) */
static struct opt_name *opt_names_alpha[ARG_COUNT + 1];
#define MAX_LINE 1024 #define MAX_LINE 1024
#define MAX_LINE_ARGC 256 #define MAX_LINE_ARGC 256
#define REQUIRED 1 #define DESC_LINE 256
#define OPTIONAL 0
#define REQUIRED 1 /* required option */
#define OPTIONAL 0 /* optional option */
#define IGNORE -1 /* ignore option */
struct oo_line { struct oo_line {
char *name; char *name;
@@ -543,6 +552,13 @@ static int is_oo_line(char *str)
return 0; return 0;
} }
static int is_io_line(char *str)
{
if (!strncmp(str, "IO:", 3))
return 1;
return 0;
}
static int is_op_line(char *str) static int is_op_line(char *str)
{ {
if (!strncmp(str, "OP:", 3)) if (!strncmp(str, "OP:", 3))
@@ -608,8 +624,12 @@ static void set_pos_def(struct command *cmd, char *str, struct arg_def *def)
if ((val_enum == lv_VAL) && strstr(name, "_")) if ((val_enum == lv_VAL) && strstr(name, "_"))
def->lvt_bits = lv_to_bits(name); def->lvt_bits = lv_to_bits(name);
if (strstr(name, "_new")) if (strstr(name, "_new")) {
def->flags |= ARG_DEF_FLAG_NEW; if (val_enum == lv_VAL)
def->flags |= ARG_DEF_FLAG_NEW_LV;
else if (val_enum == vg_VAL)
def->flags |= ARG_DEF_FLAG_NEW_VG;
}
} }
} }
@@ -661,9 +681,12 @@ static void set_opt_def(struct command *cmd, char *str, struct arg_def *def)
def->lvt_bits = lv_to_bits(name); def->lvt_bits = lv_to_bits(name);
} }
if ((val_enum == vg_VAL) || (val_enum == lv_VAL) || (val_enum == pv_VAL)) { if (strstr(name, "_new")) {
if (strstr(name, "_new")) if (val_enum == lv_VAL)
def->flags |= ARG_DEF_FLAG_NEW; def->flags |= ARG_DEF_FLAG_NEW_LV;
else if (val_enum == vg_VAL)
def->flags |= ARG_DEF_FLAG_NEW_VG;
} }
} }
} }
@@ -788,10 +811,14 @@ static void add_opt_arg(struct command *cmd, char *str, int *takes_arg, int requ
opt = opt_str_to_num(str); opt = opt_str_to_num(str);
skip: skip:
if (required) if (required > 0)
cmd->required_opt_args[cmd->ro_count++].opt = opt; cmd->required_opt_args[cmd->ro_count++].opt = opt;
else else if (!required)
cmd->optional_opt_args[cmd->oo_count++].opt = opt; cmd->optional_opt_args[cmd->oo_count++].opt = opt;
else if (required < 0)
cmd->ignore_opt_args[cmd->io_count++].opt = opt;
else
exit(1);
*takes_arg = opt_names[opt].val_enum ? 1 : 0; *takes_arg = opt_names[opt].val_enum ? 1 : 0;
} }
@@ -814,10 +841,14 @@ static void update_prev_opt_arg(struct command *cmd, char *str, int required)
set_opt_def(cmd, str, &def); set_opt_def(cmd, str, &def);
if (required) if (required > 0)
cmd->required_opt_args[cmd->ro_count-1].def = def; cmd->required_opt_args[cmd->ro_count-1].def = def;
else else if (!required)
cmd->optional_opt_args[cmd->oo_count-1].def = def; cmd->optional_opt_args[cmd->oo_count-1].def = def;
else if (required < 0)
cmd->ignore_opt_args[cmd->io_count-1].def = def;
else
exit(1);
} }
static void add_pos_arg(struct command *cmd, char *str, int required) static void add_pos_arg(struct command *cmd, char *str, int required)
@@ -882,6 +913,24 @@ static void add_optional_opt_line(struct command *cmd, int argc, char *argv[])
} }
} }
static void add_ignore_opt_line(struct command *cmd, int argc, char *argv[])
{
int takes_arg;
int i;
for (i = 0; i < argc; i++) {
if (!i && !strncmp(argv[i], "IO:", 3))
continue;
if (is_opt_name(argv[i]))
add_opt_arg(cmd, argv[i], &takes_arg, IGNORE);
else if (takes_arg)
update_prev_opt_arg(cmd, argv[i], IGNORE);
else
printf("Can't parse argc %d argv %s prev %s\n",
i, argv[i], argv[i-1]);
}
}
/* process what follows OP:, which are optional pos args */ /* process what follows OP:, which are optional pos args */
static void add_optional_pos_line(struct command *cmd, int argc, char *argv[]) static void add_optional_pos_line(struct command *cmd, int argc, char *argv[])
@@ -1007,10 +1056,10 @@ static void print_def(struct arg_def *def, int usage)
} }
} }
if ((val_enum == pv_VAL) || (val_enum == vg_VAL) || (val_enum == lv_VAL)) { if ((val_enum == vg_VAL) && (def->flags & ARG_DEF_FLAG_NEW_VG))
if (def->flags & ARG_DEF_FLAG_NEW) printf("_new");
printf("_new"); if ((val_enum == lv_VAL) && (def->flags & ARG_DEF_FLAG_NEW_LV))
} printf("_new");
} }
} }
@@ -1147,10 +1196,15 @@ static char *flags_to_str(int flags)
strcat(buf_flags, " | "); strcat(buf_flags, " | ");
strcat(buf_flags, "ARG_DEF_FLAG_MAY_REPEAT"); strcat(buf_flags, "ARG_DEF_FLAG_MAY_REPEAT");
} }
if (flags & ARG_DEF_FLAG_NEW) { if (flags & ARG_DEF_FLAG_NEW_VG) {
if (buf_flags[0]) if (buf_flags[0])
strcat(buf_flags, " | "); strcat(buf_flags, " | ");
strcat(buf_flags, "ARG_DEF_FLAG_NEW"); strcat(buf_flags, "ARG_DEF_FLAG_NEW_VG");
}
if (flags & ARG_DEF_FLAG_NEW_LV) {
if (buf_flags[0])
strcat(buf_flags, " | ");
strcat(buf_flags, "ARG_DEF_FLAG_NEW_LV");
} }
return buf_flags; return buf_flags;
@@ -1672,12 +1726,15 @@ static void print_def_man(struct arg_def *def, int usage)
printf("\\fP"); printf("\\fP");
} }
if ((val_enum == pv_VAL) || (val_enum == vg_VAL) || (val_enum == lv_VAL)) { if ((val_enum == vg_VAL) && (def->flags & ARG_DEF_FLAG_NEW_VG)) {
if (def->flags & ARG_DEF_FLAG_NEW) { printf("\\fI");
printf("\\fI"); printf("_new");
printf("_new"); printf("\\fP");
printf("\\fP"); }
} if ((val_enum == lv_VAL) && (def->flags & ARG_DEF_FLAG_NEW_LV)) {
printf("\\fI");
printf("_new");
printf("\\fP");
} }
} }
} }
@@ -2000,6 +2057,23 @@ void print_man_usage(struct command *cmd)
printf("\n"); printf("\n");
} }
/*
* common options listed in the usage section.
*
* For commands with only one variant, this is only
* the options which are common to all lvm commands
* (in lvm_all, see is_lvm_all_opt).
*
* For commands with more than one variant, this
* is the set of options common to all variants
* (in cname->common_options), (which obviously
* includes the options common to all lvm commands.)
*
* List ordering:
* options with short+long names, alphabetically,
* then options with only long names, alphabetically
*/
void print_man_usage_common(struct command *cmd) void print_man_usage_common(struct command *cmd)
{ {
struct cmd_name *cname; struct cmd_name *cname;
@@ -2013,23 +2087,17 @@ void print_man_usage_common(struct command *cmd)
printf(".RS 4\n"); printf(".RS 4\n");
printf("["); printf("[");
/*
* when there's more than one variant, options that
* are common to all commands with a common name.
*/
if (cname->variants < 2)
goto all;
/* print those with short opts */ /* print those with short opts */
for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) { for (i = 0; i < ARG_COUNT; i++) {
opt_enum = opt_names_alpha[i]->opt_enum;
if (!cname->common_options[opt_enum]) if (!cname->common_options[opt_enum])
continue; continue;
if (!opt_names[opt_enum].short_opt) if (!opt_names[opt_enum].short_opt)
continue; continue;
if (is_lvm_all_opt(opt_enum)) if ((cname->variants < 2) && !is_lvm_all_opt(opt_enum))
continue; continue;
if (sep) { if (sep) {
@@ -2057,14 +2125,16 @@ void print_man_usage_common(struct command *cmd)
} }
/* print those without short opts */ /* print those without short opts */
for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) { for (i = 0; i < ARG_COUNT; i++) {
opt_enum = opt_names_alpha[i]->opt_enum;
if (!cname->common_options[opt_enum]) if (!cname->common_options[opt_enum])
continue; continue;
if (opt_names[opt_enum].short_opt) if (opt_names[opt_enum].short_opt)
continue; continue;
if (is_lvm_all_opt(opt_enum)) if ((cname->variants < 2) && !is_lvm_all_opt(opt_enum))
continue; continue;
if (sep) { if (sep) {
@@ -2090,67 +2160,108 @@ void print_man_usage_common(struct command *cmd)
break; break;
} }
} }
all:
/* options that are common to all lvm commands */
/* those with short opts */
for (oo = 0; oo < lvm_all.oo_count; oo++) {
opt_enum = lvm_all.optional_opt_args[oo].opt;
if (!opt_names[opt_enum].short_opt)
continue;
if (sep) {
printf(",");
printf("\n.br\n");
printf(" ");
}
printf(" \\fB-%c\\fP|\\fB%s\\fP",
opt_names[opt_enum].short_opt,
man_long_opt_name(cmd->name, opt_enum));
if (lvm_all.optional_opt_args[oo].def.val_bits) {
printf(" ");
print_def(&lvm_all.optional_opt_args[oo].def, 1);
}
sep = 1;
}
/* those without short opts */
for (oo = 0; oo < lvm_all.oo_count; oo++) {
opt_enum = lvm_all.optional_opt_args[oo].opt;
if (opt_names[opt_enum].short_opt)
continue;
if (sep) {
printf(",");
printf("\n.br\n");
printf(" ");
}
/* space alignment without short opt */
printf(" ");
printf(" \\fB%s\\fP", man_long_opt_name(cmd->name, opt_enum));
if (lvm_all.optional_opt_args[oo].def.val_bits) {
printf(" ");
print_def(&lvm_all.optional_opt_args[oo].def, 1);
}
sep = 1;
}
printf(" ]\n"); printf(" ]\n");
return;
} }
void print_man_all_options(struct cmd_name *cname) /*
* Format of description, when different command names have
* different descriptions:
*
* "#cmdname1"
* "text foo goes here"
* "a second line of text."
* "#cmdname2"
* "text bar goes here"
* "another line of text."
*
* When called for cmdname2, this function should just print:
*
* "text bar goes here"
* "another line of text."
*/
static void print_man_option_desc(struct cmd_name *cname, int opt_enum)
{
const char *desc = opt_names[opt_enum].desc;
char buf[DESC_LINE];
int started_cname = 0;
int line_count = 0;
int di, bi;
if (desc[0] != '#') {
printf("%s", desc);
return;
}
for (di = 0; di < strlen(desc); di++) {
buf[bi++] = desc[di];
if (bi == DESC_LINE) {
printf("print_man_option_desc line too long\n");
return;
}
if (buf[bi-1] != '\n')
continue;
if (buf[0] != '#') {
if (started_cname) {
printf("%s", buf);
line_count++;
}
memset(buf, 0, sizeof(buf));
bi = 0;
continue;
}
/* Line starting with #cmdname */
/*
* Must be starting a new command name.
* If no lines have been printed, multiple command names
* are using the same text. If lines have been printed,
* then the start of a new command name means the end
* of text for the current command name.
*/
if (line_count && started_cname)
return;
if (!strncmp(buf + 1, cname->name, strlen(cname->name))) {
/* The start of our command name. */
started_cname = 1;
memset(buf, 0, sizeof(buf));
bi = 0;
} else {
/* The start of another command name. */
memset(buf, 0, sizeof(buf));
bi = 0;
}
}
if (bi && started_cname)
printf("%s", buf);
}
/*
* Print a list of all options names for a given
* command name, listed by:
* options with short+long names, alphabetically,
* then options with only long names, alphabetically
*/
void print_man_all_options_list(struct cmd_name *cname)
{ {
int opt_enum, val_enum; int opt_enum, val_enum;
int sep = 0; int sep = 0;
int i;
/* print those with both short and long opts */
for (i = 0; i < ARG_COUNT; i++) {
opt_enum = opt_names_alpha[i]->opt_enum;
/* print those with short opts */
for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) {
if (!cname->all_options[opt_enum]) if (!cname->all_options[opt_enum])
continue; continue;
@@ -2182,7 +2293,9 @@ void print_man_all_options(struct cmd_name *cname)
} }
/* print those without short opts */ /* print those without short opts */
for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) { for (i = 0; i < ARG_COUNT; i++) {
opt_enum = opt_names_alpha[i]->opt_enum;
if (!cname->all_options[opt_enum]) if (!cname->all_options[opt_enum])
continue; continue;
@@ -2215,7 +2328,79 @@ void print_man_all_options(struct cmd_name *cname)
} }
} }
#define DESC_LINE 256 /*
* All options used for a given command name, along with descriptions.
* listed in order of:
* 1. options that are not common to all lvm commands, alphabetically
* 2. options common to all lvm commands, alphabetically
*/
void print_man_all_options_desc(struct cmd_name *cname)
{
int opt_enum, val_enum;
int print_common = 0;
int sep = 0;
int i;
again:
/*
* Loop 1: print options that are not common to all lvm commands.
* Loop 2: print options common to all lvm commands (lvm_all)
*/
for (i = 0; i < ARG_COUNT; i++) {
opt_enum = opt_names_alpha[i]->opt_enum;
if (!cname->all_options[opt_enum])
continue;
if (!print_common && is_lvm_all_opt(opt_enum))
continue;
if (print_common && !is_lvm_all_opt(opt_enum))
continue;
if (sep)
printf("\n.br\n");
printf("\n.TP\n");
if (opt_names[opt_enum].short_opt) {
printf("\\fB-%c\\fP|\\fB%s\\fP",
opt_names[opt_enum].short_opt,
man_long_opt_name(cname->name, opt_enum));
} else {
printf("\\fB%s\\fP", man_long_opt_name(cname->name, opt_enum));
}
val_enum = opt_names[opt_enum].val_enum;
if (!val_names[val_enum].fn) {
/* takes no arg */
} else if (!val_names[val_enum].usage) {
printf(" ");
printf("\\fI");
printf("%s", val_names[val_enum].name);
printf("\\fP");
} else {
printf(" ");
print_val_man(val_names[val_enum].usage);
}
if (opt_names[opt_enum].desc) {
printf("\n");
printf(".br\n");
print_man_option_desc(cname, opt_enum);
}
sep = 1;
}
if (!print_common) {
print_common = 1;
goto again;
}
}
void print_desc_man(const char *desc) void print_desc_man(const char *desc)
{ {
@@ -2288,6 +2473,12 @@ void print_man_command(void)
printf("Common options:\n"); printf("Common options:\n");
printf(".\n"); printf(".\n");
print_man_usage_common(prev_cmd); print_man_usage_common(prev_cmd);
printf("\n");
printf(".SH OPTIONS\n");
printf(".br\n");
print_man_all_options_desc(cname);
prev_cmd = NULL; prev_cmd = NULL;
} }
@@ -2346,7 +2537,7 @@ void print_man_command(void)
/* listing them all when there's only 1 or 2 is just repetative */ /* listing them all when there's only 1 or 2 is just repetative */
if (cname->variants > 2) { if (cname->variants > 2) {
printf(".P\n"); printf(".P\n");
print_man_all_options(cname); print_man_all_options_list(cname);
printf("\n"); printf("\n");
printf(".P\n"); printf(".P\n");
printf("\n"); printf("\n");
@@ -2369,6 +2560,12 @@ void print_man_command(void)
printf("Common options:\n"); printf("Common options:\n");
printf(".\n"); printf(".\n");
print_man_usage_common(cmd); print_man_usage_common(cmd);
printf("\n");
printf(".SH OPTIONS\n");
printf(".br\n");
print_man_all_options_desc(cname);
} }
printf("\n"); printf("\n");
@@ -2379,7 +2576,7 @@ void print_man_command(void)
void print_command_struct(int only_usage) void print_command_struct(int only_usage)
{ {
struct command *cmd; struct command *cmd;
int i, j, ro, rp, oo, op, ru, ruo; int i, j, ro, rp, oo, op, ru, ruo, io;
include_optional_opt_args(&lvm_all, "OO_USAGE_COMMON"); include_optional_opt_args(&lvm_all, "OO_USAGE_COMMON");
@@ -2405,6 +2602,7 @@ void print_command_struct(int only_usage)
printf("commands[%d].rp_count = %d;\n", i, cmd->rp_count); printf("commands[%d].rp_count = %d;\n", i, cmd->rp_count);
printf("commands[%d].oo_count = %d;\n", i, cmd->oo_count); printf("commands[%d].oo_count = %d;\n", i, cmd->oo_count);
printf("commands[%d].op_count = %d;\n", i, cmd->op_count); printf("commands[%d].op_count = %d;\n", i, cmd->op_count);
printf("commands[%d].io_count = %d;\n", i, cmd->io_count);
printf("commands[%d].rule_count = %d;\n", i, cmd->rule_count); printf("commands[%d].rule_count = %d;\n", i, cmd->rule_count);
if (cmd->cmd_flags) if (cmd->cmd_flags)
@@ -2510,6 +2708,35 @@ void print_command_struct(int only_usage)
} }
} }
if (cmd->io_count) {
for (io = 0; io < cmd->io_count; io++) {
printf("commands[%d].ignore_opt_args[%d].opt = %s;\n",
i, io, opt_to_enum_str(cmd->ignore_opt_args[io].opt));
if (!cmd->ignore_opt_args[io].def.val_bits)
continue;
printf("commands[%d].ignore_opt_args[%d].def.val_bits = %s;\n",
i, io, val_bits_to_str(cmd->ignore_opt_args[io].def.val_bits));
if (cmd->ignore_opt_args[io].def.lvt_bits)
printf("commands[%d].ignore_opt_args[%d].def.lvt_bits = %s;\n",
i, io, lvt_bits_to_str(cmd->ignore_opt_args[io].def.lvt_bits));
if (cmd->ignore_opt_args[io].def.flags)
printf("commands[%d].ignore_opt_args[%d].def.flags = %s;\n",
i, io, flags_to_str(cmd->ignore_opt_args[io].def.flags));
if (val_bit_is_set(cmd->ignore_opt_args[io].def.val_bits, constnum_VAL))
printf("commands[%d].ignore_opt_args[%d].def.num = %d;\n",
i, io, cmd->ignore_opt_args[io].def.num);
if (val_bit_is_set(cmd->ignore_opt_args[io].def.val_bits, conststr_VAL))
printf("commands[%d].ignore_opt_args[%d].def.str = \"%s\";\n",
i, io, cmd->ignore_opt_args[io].def.str ?: "NULL");
}
}
if (cmd->op_count) { if (cmd->op_count) {
for (op = 0; op < cmd->op_count; op++) { for (op = 0; op < cmd->op_count; op++) {
printf("commands[%d].optional_pos_args[%d].pos = %d;\n", printf("commands[%d].optional_pos_args[%d].pos = %d;\n",
@@ -2650,6 +2877,23 @@ next:
} }
} }
static int long_name_compare(const void *on1, const void *on2)
{
struct opt_name **optname1 = (void *)on1;
struct opt_name **optname2 = (void *)on2;
return strcmp((*optname1)->long_opt + 2, (*optname2)->long_opt + 2);
}
static void create_opt_names_alpha(void)
{
int i;
for (i = 0; i < ARG_COUNT; i++)
opt_names_alpha[i] = &opt_names[i];
qsort(opt_names_alpha, ARG_COUNT, sizeof(long), long_name_compare);
}
void print_command_list(void) void print_command_list(void)
{ {
int i; int i;
@@ -2674,15 +2918,31 @@ void print_option_list(void)
opt_names[i].short_opt ? opt_names[i].short_opt : 0); opt_names[i].short_opt ? opt_names[i].short_opt : 0);
} }
void print_option_alpha_list(void)
{
int i;
for (i = 0; i < ARG_COUNT; i++)
printf("%d %s %s %c (%d)\n",
opt_names_alpha[i]->opt_enum, opt_names_alpha[i]->name,
opt_names_alpha[i]->long_opt, opt_names_alpha[i]->short_opt ?: ' ',
opt_names_alpha[i]->short_opt ? opt_names_alpha[i]->short_opt : 0);
}
static void print_help(int argc, char *argv[]) static void print_help(int argc, char *argv[])
{ {
printf("%s --output struct|count|usage|expanded <filename>\n", argv[0]); printf("%s [options] --output <format> <filename>\n", argv[0]);
printf("\n"); printf("\n");
printf("output formats:\n");
printf("struct: print C structures for command-lines.h\n"); printf("struct: print C structures for command-lines.h\n");
printf("count: print defines and enums for command-lines-count.h\n"); printf("count: print defines and enums for command-lines-count.h\n");
printf("ambiguous: print commands differing only by LV types\n"); printf("ambiguous: print commands differing only by LV types\n");
printf("usage: print usage format.\n"); printf("usage: print usage format.\n");
printf("expanded: print expanded input format.\n"); printf("expanded: print expanded input format.\n");
printf("man: print man page format.\n");
printf("\n");
printf("options:\n");
printf("-c|--man-command <commandname> man output for one command name\n");
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
@@ -2706,9 +2966,12 @@ int main(int argc, char *argv[])
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
create_opt_names_alpha();
if (!strcmp(argv[1], "debug")) { if (!strcmp(argv[1], "debug")) {
print_command_list(); print_command_list();
print_option_list(); print_option_list();
print_option_alpha_list();
return 0; return 0;
} }
@@ -2852,6 +3115,14 @@ int main(int argc, char *argv[])
continue; continue;
} }
/* IO: ... */
if (is_io_line(line_argv[0])) {
add_ignore_opt_line(cmd, line_argc, line_argv);
prev_was_oo = 0;
prev_was_op = 0;
continue;
}
/* handle OO_FOO:, OO:, OP: continuing on multiple lines */ /* handle OO_FOO:, OO:, OP: continuing on multiple lines */
if (prev_was_oo_def) { if (prev_was_oo_def) {

View File

@@ -370,7 +370,7 @@ static int _lvchange_resync(struct cmd_context *cmd, struct logical_volume *lv)
/* Separate mirror log or metadata devices so we can clear them */ /* Separate mirror log or metadata devices so we can clear them */
if (!detach_metadata_devices(seg, &device_list)) { if (!detach_metadata_devices(seg, &device_list)) {
log_error("Failed to clear %s %s for %s.", log_error("Failed to clear %s %s for %s.",
seg->segtype->name, seg_is_raid(seg) ? lvseg_name(seg), seg_is_raid(seg) ?
"metadata area" : "mirror log", display_lvname(lv)); "metadata area" : "mirror log", display_lvname(lv));
return 0; return 0;
} }
@@ -1022,6 +1022,12 @@ static int _lvchange_properties_check(struct cmd_context *cmd,
return 0; return 0;
} }
if (vg_is_clustered(lv->vg) && lv_is_cache_origin(lv) && lv_is_raid(lv)) {
log_error("Unable to change internal LV %s directly in a cluster.",
display_lvname(lv));
return 0;
}
return 1; return 1;
} }

View File

@@ -2125,10 +2125,17 @@ static int _lvconvert_merge_old_snapshot(struct cmd_context *cmd,
if (!lv_update_and_reload(origin)) if (!lv_update_and_reload(origin))
return_0; return_0;
if (!lv_info(cmd, origin, 0, &info, 0, 0) || !info.exists) if (!lv_has_target_type(origin->vg->vgmem, origin, NULL,
TARGET_NAME_SNAPSHOT_MERGE)) {
/* Race during table reload prevented merging */
merge_on_activate = 1;
} else if (!lv_info(cmd, origin, 0, &info, 0, 0) || !info.exists) {
log_print_unless_silent("Conversion starts after activation."); log_print_unless_silent("Conversion starts after activation.");
else merge_on_activate = 1;
} else {
*lv_to_poll = origin; *lv_to_poll = origin;
}
} }
if (merge_on_activate) if (merge_on_activate)

View File

@@ -210,7 +210,7 @@ int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline)
{ {
log_report_t saved_log_report_state = log_get_report_state(); log_report_t saved_log_report_state = log_get_report_state();
char *orig_command_log_selection = NULL; char *orig_command_log_selection = NULL;
int is_lastlog_cmd = 0, argc, ret; int is_lastlog_cmd = 0, argc, ret, i;
char *input = NULL, *args[MAX_ARGS], **argv; char *input = NULL, *args[MAX_ARGS], **argv;
rl_readline_name = "lvm"; rl_readline_name = "lvm";
@@ -262,6 +262,9 @@ int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline)
add_history(input); add_history(input);
for (i = 0; i < MAX_ARGS; i++)
args[i] = NULL;
argv = args; argv = args;
if (lvm_split(input, &argc, argv, MAX_ARGS) == MAX_ARGS) { if (lvm_split(input, &argc, argv, MAX_ARGS) == MAX_ARGS) {

View File

@@ -64,7 +64,7 @@ static struct val_props _val_props[VAL_COUNT + 1] = {
* Table of valid --option's * Table of valid --option's
*/ */
static struct arg_props _arg_props[ARG_COUNT + 1] = { static struct arg_props _arg_props[ARG_COUNT + 1] = {
#define arg(a, b, c, d, e, f) {a, b, "", "--" c, d, e, f}, #define arg(a, b, c, d, e, f, g) {a, b, "", "--" c, d, e, f, g},
#include "args.h" #include "args.h"
#undef arg #undef arg
}; };
@@ -655,6 +655,14 @@ int int_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *
return 1; return 1;
} }
int uint32_arg(struct cmd_context *cmd, struct arg_values *av)
{
if (!int_arg(cmd, av) || (av->ui64_value > UINT32_MAX))
return 0;
return 1;
}
int int_arg_with_sign(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) int int_arg_with_sign(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av)
{ {
char *ptr; char *ptr;
@@ -1154,6 +1162,25 @@ static int _opt_synonym_is_set(struct cmd_context *cmd, int opt_std)
return opt_syn && arg_is_set(cmd, opt_syn); return opt_syn && arg_is_set(cmd, opt_syn);
} }
static int _command_ignore_opt_matches(struct cmd_context *cmd, int ci, int io)
{
int opt_enum = commands[ci].ignore_opt_args[io].opt;
if (val_bit_is_set(commands[ci].ignore_opt_args[io].def.val_bits, conststr_VAL)) {
if (!strcmp(commands[ci].ignore_opt_args[io].def.str, arg_str_value(cmd, opt_enum, "")))
return 1;
return 0;
}
if (val_bit_is_set(commands[ci].ignore_opt_args[io].def.val_bits, constnum_VAL)) {
if (commands[ci].ignore_opt_args[io].def.num == arg_int_value(cmd, opt_enum, 0))
return 1;
return 0;
}
return 1;
}
static int _command_required_opt_matches(struct cmd_context *cmd, int ci, int ro) static int _command_required_opt_matches(struct cmd_context *cmd, int ci, int ro)
{ {
int opt_enum = commands[ci].required_opt_args[ro].opt; int opt_enum = commands[ci].required_opt_args[ro].opt;
@@ -1261,7 +1288,7 @@ static int _command_required_pos_matches(struct cmd_context *cmd, int ci, int rp
#define HELP_LINE_SIZE 1024 #define HELP_LINE_SIZE 1024
static void _print_usage(const char *usage, int only_required) static void _print_usage(const char *usage_str, int only_required)
{ {
char buf[HELP_LINE_SIZE]; char buf[HELP_LINE_SIZE];
int optional_ui = 0; int optional_ui = 0;
@@ -1269,7 +1296,7 @@ static void _print_usage(const char *usage, int only_required)
int ui; int ui;
int bi; int bi;
if (!usage || !strlen(usage)) if (!usage_str || !strlen(usage_str))
return; return;
/* /*
@@ -1286,32 +1313,32 @@ static void _print_usage(const char *usage, int only_required)
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
bi = 0; bi = 0;
for (ui = 0; ui < strlen(usage); ui++) { for (ui = 0; ui < strlen(usage_str); ui++) {
if (!bi && ((usage[ui] == ' ') || (usage[ui] == '\n'))) if (!bi && ((usage_str[ui] == ' ') || (usage_str[ui] == '\n')))
continue; continue;
/* The first "[ " indicates the start of the optional opt_args. */ /* The first "[ " indicates the start of the optional opt_args. */
if ((usage[ui] == '[') && (usage[ui+1] == ' ')) { if ((usage_str[ui] == '[') && (usage_str[ui+1] == ' ')) {
optional_ui = ui; optional_ui = ui;
break; break;
} }
if (usage[ui] == '\0') if (usage_str[ui] == '\0')
break; break;
if (usage[ui] == '(') { if (usage_str[ui] == '(') {
buf[bi++] = '\n'; buf[bi++] = '\n';
buf[bi++] = '\t'; buf[bi++] = '\t';
} }
buf[bi++] = usage[ui]; buf[bi++] = usage_str[ui];
if (usage[ui] == ')') { if (usage_str[ui] == ')') {
buf[bi++] = '\n'; buf[bi++] = '\n';
buf[bi++] = '\t'; buf[bi++] = '\t';
} }
if (usage[ui] == ',') { if (usage_str[ui] == ',') {
buf[bi++] = '\n'; buf[bi++] = '\n';
buf[bi++] = '\t'; buf[bi++] = '\t';
buf[bi++] = ' '; buf[bi++] = ' ';
@@ -1341,25 +1368,25 @@ static void _print_usage(const char *usage, int only_required)
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
bi = 0; bi = 0;
for (ui = optional_ui; ui < strlen(usage); ui++) { for (ui = optional_ui; ui < strlen(usage_str); ui++) {
/* The second "[ " indicates the start of the optional pos_args. */ /* The second "[ " indicates the start of the optional pos_args. */
if ((ui > optional_ui) && (usage[ui] == '[') && (usage[ui+1] == ' ')) { if ((ui > optional_ui) && (usage_str[ui] == '[') && (usage_str[ui+1] == ' ')) {
optional_pos_ui = ui; optional_pos_ui = ui;
break; break;
} }
if (usage[ui] == '\0') if (usage_str[ui] == '\0')
break; break;
if (usage[ui] == '\n') if (usage_str[ui] == '\n')
break; break;
if (!bi) if (!bi)
buf[bi++] = '\t'; buf[bi++] = '\t';
buf[bi++] = usage[ui]; buf[bi++] = usage_str[ui];
if (usage[ui] == ',') { if (usage_str[ui] == ',') {
buf[bi++] = '\n'; buf[bi++] = '\n';
buf[bi++] = '\t'; buf[bi++] = '\t';
buf[bi++] = ' '; buf[bi++] = ' ';
@@ -1386,16 +1413,16 @@ static void _print_usage(const char *usage, int only_required)
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
bi = 0; bi = 0;
for (ui = optional_pos_ui; ui < strlen(usage); ui++) { for (ui = optional_pos_ui; ui < strlen(usage_str); ui++) {
if (usage[ui] == '\0') if (usage_str[ui] == '\0')
break; break;
if (usage[ui] == '\n') if (usage_str[ui] == '\n')
break; break;
if (!bi) if (!bi)
buf[bi++] = '\t'; buf[bi++] = '\t';
buf[bi++] = usage[ui]; buf[bi++] = usage_str[ui];
if (bi == (HELP_LINE_SIZE - 1)) if (bi == (HELP_LINE_SIZE - 1))
break; break;
@@ -1615,6 +1642,14 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path,
} }
} }
for (j = 0; j < commands[i].io_count; j++) {
if ((commands[i].ignore_opt_args[j].opt == opt_enum) &&
_command_ignore_opt_matches(cmd, i, j)) {
accepted = 1;
break;
}
}
if (!accepted) { if (!accepted) {
match_unused++; match_unused++;
if (temp_unused_count < MAX_UNUSED_COUNT) if (temp_unused_count < MAX_UNUSED_COUNT)
@@ -1822,9 +1857,12 @@ static int _usage(const char *name, int help_count)
log_print(". The _new suffix indicates the VG or LV must not yet exist."); log_print(". The _new suffix indicates the VG or LV must not yet exist.");
log_print(". LV followed by _<type> indicates that an LV of the given type"); log_print(". LV followed by _<type> indicates that an LV of the given type");
log_print(" is required. (raid represents any raid<N> type.)"); log_print(" is required. (raid represents any raid<N> type.)");
log_print(". The default output unit is specified by letter, followed by |unit"); log_print(". Input units are always treated as base two values, regardless of");
log_print(" which represents other possible units: hHbBsSkKmMgGtTpPeE."); log_print(" unit capitalization, e.g. 'k' and 'K' both refer to 1024.");
log_print(". Output units are 1024 SI base, regardless of unit capitalization."); log_print(". The default input unit is specified by letter, followed by |unit");
log_print(" which represents other possible input units: bBsSkKmMgGtTpPeE.");
log_print(". Output units can be specified with the --units option, for which");
log_print(" lower/upper case letters refer to base 2/10 values.");
log_print(". Use --help --help --help to print secondary command syntax"); log_print(". Use --help --help --help to print secondary command syntax");
log_print(" formats that are recognized, e.g. for compatibility."); log_print(" formats that are recognized, e.g. for compatibility.");
log_print(". See man pages for short option equivalents of long option names,"); log_print(". See man pages for short option equivalents of long option names,");

View File

@@ -113,6 +113,40 @@ static int _do_info_and_status(struct cmd_context *cmd,
return 1; return 1;
} }
/* Check if this is really merging origin.
* In such case, origin is gone, and user should see
* only data from merged snapshot. Important for thin. */
static int _check_merging_origin(const struct logical_volume *lv,
struct lv_with_info_and_seg_status *status,
int *merged)
{
uint32_t device_id;
*merged = 0;
switch (status->seg_status.type) {
case SEG_STATUS_THIN:
/* Get 'device_id' from active dm-table */
if (!lv_thin_device_id(lv, &device_id))
return_0;
if (lv->snapshot->device_id != device_id)
return 1;
break;
case SEG_STATUS_SNAPSHOT:
break;
default:
return 1;
}
/* Origin is gone */
log_debug_activation("Merge is progress, reporting merged LV %s.",
display_lvname(lv->snapshot->lv));
*merged = 1;
return 1;
}
static int _do_lvs_with_info_and_status_single(struct cmd_context *cmd, static int _do_lvs_with_info_and_status_single(struct cmd_context *cmd,
const struct logical_volume *lv, const struct logical_volume *lv,
int do_info, int do_status, int do_info, int do_status,
@@ -123,10 +157,22 @@ static int _do_lvs_with_info_and_status_single(struct cmd_context *cmd,
.seg_status.type = SEG_STATUS_NONE .seg_status.type = SEG_STATUS_NONE
}; };
int r = ECMD_FAILED; int r = ECMD_FAILED;
int merged;
if (lv_is_merging_origin(lv))
/* Status is need to know which LV should be shown */
do_status = 1;
if (!_do_info_and_status(cmd, first_seg(lv), &status, do_info, do_status)) if (!_do_info_and_status(cmd, first_seg(lv), &status, do_info, do_status))
goto_out; goto_out;
if (lv_is_merging_origin(lv)) {
if (!_check_merging_origin(lv, &status, &merged))
goto_out;
if (merged)
lv = lv->snapshot->lv;
}
if (!report_object(sh ? : handle->custom_handle, sh != NULL, if (!report_object(sh ? : handle->custom_handle, sh != NULL,
lv->vg, lv, NULL, NULL, NULL, &status, NULL)) lv->vg, lv, NULL, NULL, NULL, &status, NULL))
goto out; goto out;
@@ -173,10 +219,22 @@ static int _do_segs_with_info_and_status_single(struct cmd_context *cmd,
.seg_status.type = SEG_STATUS_NONE .seg_status.type = SEG_STATUS_NONE
}; };
int r = ECMD_FAILED; int r = ECMD_FAILED;
int merged;
if (lv_is_merging_origin(seg->lv))
/* Status is need to know which LV should be shown */
do_status = 1;
if (!_do_info_and_status(cmd, seg, &status, do_info, do_status)) if (!_do_info_and_status(cmd, seg, &status, do_info, do_status))
goto_out; goto_out;
if (lv_is_merging_origin(seg->lv)) {
if (!_check_merging_origin(seg->lv, &status, &merged))
goto_out;
if (merged)
seg = seg->lv->snapshot;
}
if (!report_object(sh ? : handle->custom_handle, sh != NULL, if (!report_object(sh ? : handle->custom_handle, sh != NULL,
seg->lv->vg, seg->lv, NULL, seg, NULL, &status, NULL)) seg->lv->vg, seg->lv, NULL, seg, NULL, &status, NULL))
goto_out; goto_out;

View File

@@ -59,7 +59,7 @@ enum {
/* define the enums for the command line --options, foo_ARG */ /* define the enums for the command line --options, foo_ARG */
enum { enum {
#define arg(a, b, c, d, e, f) a , #define arg(a, b, c, d, e, f, g) a ,
#include "args.h" #include "args.h"
#undef arg #undef arg
}; };
@@ -109,6 +109,7 @@ struct arg_props {
int val_enum; /* foo_VAL from vals.h */ int val_enum; /* foo_VAL from vals.h */
uint32_t flags; uint32_t flags;
uint32_t prio; uint32_t prio;
const char *desc;
}; };
struct arg_value_group_list { struct arg_value_group_list {
@@ -177,6 +178,7 @@ int size_kb_arg(struct cmd_context *cmd, struct arg_values *av);
int size_mb_arg(struct cmd_context *cmd, struct arg_values *av); int size_mb_arg(struct cmd_context *cmd, struct arg_values *av);
int size_mb_arg_with_percent(struct cmd_context *cmd, struct arg_values *av); int size_mb_arg_with_percent(struct cmd_context *cmd, struct arg_values *av);
int int_arg(struct cmd_context *cmd, struct arg_values *av); int int_arg(struct cmd_context *cmd, struct arg_values *av);
int uint32_arg(struct cmd_context *cmd, struct arg_values *av);
int int_arg_with_sign(struct cmd_context *cmd, struct arg_values *av); int int_arg_with_sign(struct cmd_context *cmd, struct arg_values *av);
int int_arg_with_sign_and_percent(struct cmd_context *cmd, struct arg_values *av); int int_arg_with_sign_and_percent(struct cmd_context *cmd, struct arg_values *av);
int major_arg(struct cmd_context *cmd, struct arg_values *av); int major_arg(struct cmd_context *cmd, struct arg_values *av);

View File

@@ -99,6 +99,7 @@ val(conststr_VAL, NULL, "ConstString", "ERR") /* used only for command defs */
val(constnum_VAL, NULL, "ConstNumber", "ERR") /* used only for command defs */ val(constnum_VAL, NULL, "ConstNumber", "ERR") /* used only for command defs */
val(bool_VAL, yes_no_arg, "Bool", "y|n") val(bool_VAL, yes_no_arg, "Bool", "y|n")
val(number_VAL, int_arg, "Number", NULL) val(number_VAL, int_arg, "Number", NULL)
val(uint32_VAL, uint32_arg, "Uint32", "Number")
val(string_VAL, string_arg, "String", NULL) val(string_VAL, string_arg, "String", NULL)
val(vg_VAL, string_arg, "VG", NULL) val(vg_VAL, string_arg, "VG", NULL)
val(lv_VAL, string_arg, "LV", NULL) val(lv_VAL, string_arg, "LV", NULL)