1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-09-23 17:44:22 +03:00

Compare commits

..

40 Commits

Author SHA1 Message Date
Bryn M. Reeves
2350ea0060 man: add update_filemap to dmstats.8.in 2017-01-25 16:15:21 +00:00
Bryn M. Reeves
b999d5f501 dmstats: allow --filemap groups to be updated
Add a new update_filemap command to dmstats that allows a filemap
group to be updated:

  # dmstats update_filemap --groupid 0 vm.img
  /var/lib/libvirt/images/vm.img: Updated group ID 0 with 137 region(s).

This will update the set of regions mapped to the file to reflect
the current file system allocation.

Currently this needs to be run manually - a future update will add
support for monitoring file maps via a daemon, allowing them to be
automatically updated when the underlying file is modified.
2017-01-25 16:15:21 +00:00
Bryn M. Reeves
e0d19feb85 libdm: add dm_stats_update_regions_from_fd()
Add a call to update the regions corresponding to a file mapped
group of regions. The regions to be updated must be grouped, to
allow us to correctly identify extents that have been deallocated
since the map was created.

Tables are built of the file extents, and the extents currently
mapped to dmstats regions: if a region no longer has a matching
file extent, it is deleted, and new regions are created for any
file extents without a matching region.

The FIEMAP call returns extents that are currently in-memory (or
journaled) and awaiting allocation in the file system. These have
the FIEMAP_EXTENT_UNKNOWN | FIEMAP_EXTENT_DELALLOC flag bits set
in the fe_flags field - these extents are skipped until they
have a known disk location.

Since it is possile for the 0th extent of the file to have been
deallocated this must also handle the possible deletion and
re-creation of the group leader: if no other region allocation
is taking place the group identifier will not change.
2017-01-25 16:15:21 +00:00
Bryn M. Reeves
1c00bb5da3 libdm: test for DM_STATS_GROUP_NOT_PRESENT in _stats_group_id_present
If the group_id passed to _stats_group_id_present is equal to the
special value DM_STATS_GROUP_NOT_PRESENT there is no need to perform
any further tests: return false immediately.
2017-01-25 15:29:35 +00:00
Bryn M. Reeves
ca427a711a libdm: fix stats comment formatting in libdevmapper.h 2017-01-24 09:29:31 +00:00
Zdenek Kabelac
ec93f37b86 toolcontext: action for LVM_RUN_BY_DMEVENTD env var
When LVM_RUN_BY_DMEVENTD is set to 1, ensure there will
be no interaction with dmeventd.
2017-01-23 14:55:47 +01:00
Zdenek Kabelac
836eb122ce dmeventd_thind: set LVM_RUN_BY_DMEVENTD
Set LVM_RUN_BY_DMEVENTD envvar to expose the command is runing from
dmeventd environment.
2017-01-23 14:55:47 +01:00
Zdenek Kabelac
4a7f2155c1 clean: move code to lib part
Move actual processing part of the lvm2_disable_dmeventd_monitoring()
into a /lib part so we can reuse the code later for other cases.
2017-01-23 14:55:28 +01:00
Zdenek Kabelac
2d48317d3a tests: umount when above 95
Add code to check if resulting data or metadata remained over 95%
and in such case invoke umount.
2017-01-21 22:53:57 +01:00
Zdenek Kabelac
e2fa90bf38 tests: properly quote heredoc
Prepend \$ for vars which should remain in script.
Also drop --lazy umount.
Move inittest call up, so mntdir and mntusedir have proper full path.
2017-01-21 19:28:06 +01:00
Zdenek Kabelac
1a2b88516b tests: implement umount in script
Since dmeventd no longer umounts thin devices, such logic
needs to be implemented by external script.
Add some very simple one for the start.
2017-01-21 17:42:19 +01:00
Zdenek Kabelac
47c11c7b1c tests: enusure units in TiB 2017-01-21 17:42:19 +01:00
Zdenek Kabelac
2e0605d6db dmeventd_thin: internal command without lvm prefix
Internal command processing needs to go without 'lvm ' prefix.
2017-01-21 17:42:19 +01:00
Zdenek Kabelac
85dab3963f dmeventd_thin: enable support for external command
With this commit we start to support configurable action
from thin-pool monitoring via  'dmeventd/thin_command'
2017-01-21 00:01:05 +01:00
Zdenek Kabelac
8c4f3633ac dmeventd_thin: new logic for calling commands
For more advanced support we need to ensure better logic for calling
external much more advanced script for maintanance of thin-pool.

So this new code ensures:

When thin-pool data or metadata is bigger then 50%,
then with each 5% increment, action is called.
This is independent from autoextend_threshold.
This action always happens when thin-pool is over threshold,
(so no action when it's exactly i.e. 60%).
The only exception is 100% full thin-pool - which invokes 'last'
action.

Since thin-pool occupancy may change also downward, code needs
to also handle possibly reduction of occupancy  of thin-pool.
So when usage drop from 90% to 50%, thin-pool will start to call
again action when it will pass 55% threshold.

This give external commands lot of option i.e. to call 'fstrim'
before actual resize is needed.
2017-01-20 23:58:56 +01:00
Zdenek Kabelac
8b95551ade dmeventd_thin: drop umounting on error path
Default internal logic will stop trying to do any 'rescue' action
when executed command fails.
This will be now fully in hands of external script if such
behaviour is needed.
2017-01-20 23:58:56 +01:00
Zdenek Kabelac
43e3268ada dmeventd_thin: rework failure handling
Instead of stopping monitoring after couple failing retries,
keep monitoring forever, just make larger delays between command
retries (ATM upto ~42 minutes).

So syslog is not spammed too often, yet commands have a chance to
be retried and succeed eventually...
2017-01-20 23:56:39 +01:00
Zdenek Kabelac
46c23dfb87 dmeventd_thin: SIGCHLD handler
To improve reaction time on when child is finished,
lets handle SIGCHLD in particular thread.
Let's hope kernel will route SIGCHLD to matching thread.
2017-01-20 23:55:51 +01:00
Zdenek Kabelac
bc7a1d70d4 dmeventd_thin: init command
When dmeventd configured command does not start with 'lvm ' prefix,
it's going to be an 'external' command.
In this case we split command by spaces to argv strings.
2017-01-20 23:55:50 +01:00
Zdenek Kabelac
14746a6c00 dmeventd_thin: add wait_pid
Add support handling command exit.
2017-01-20 23:55:50 +01:00
Zdenek Kabelac
2e935c0967 dmeventd_thin: add run_command
Implement forking of executable command.
When command is forked, dmeventd may continue monitor device.
2017-01-20 23:55:50 +01:00
Zdenek Kabelac
e5bef50827 dmeventd_thin: better warning logic
When fullness is passing WARN_THRESHOLD, print warning,
when it drops bellow and crossed again, we should print
warning again, but always only once.
2017-01-20 23:55:50 +01:00
Zdenek Kabelac
0d945ddbad dmeventd_thin: switch to struct percent
Later we can use stored percent values to pass them
to executed commands.
2017-01-20 23:55:50 +01:00
Zdenek Kabelac
eca964b554 dmeventd_thin: handling of internal command 2017-01-20 23:55:50 +01:00
Zdenek Kabelac
d80f9a107f lvmcmd2lib: support new command
Internal command which reads lvm.conf settins and passes it
via envvar to dmeventd monitoring thread.
2017-01-20 23:55:07 +01:00
Zdenek Kabelac
04a9cad499 config: new option dmeventd/thin_command
This setting will allowing configuring which command gets executed
when thin-pool fullness goes from 50%..100%
2017-01-20 23:53:26 +01:00
Zdenek Kabelac
ee754500db cleanup: update config doc 2017-01-20 23:52:40 +01:00
Zdenek Kabelac
f8234d6e5f libdm: add human R|readable units
When showing sizes with 'H|human' units we do use standard rounding.
This however is confusing users from time to time,
when the printed number uses some biger units i.e. GiB and there is just
tiny fraction of space missing.

So here is some real-life example with new 'r' unit.

$lvs

  LV    VG Attr       LSize  Pool Origin
  lvol0 vg -wi-a-----  1.99g
  lvol1 vg -wi-a----- <2.00g
  lvol2 vg -wi-a----- <2.01g

Meaning is - lvol1 has 'slightly' less then 2.00g - from sign '<' user
can be aware the LV doesn't have full 2.00GiB in size so he
will be less surpriced allocation of 2G volume will not succeed.

$ vgs
  VG #PV #LV #SN Attr   VSize  VFree
  vg   2   2   0 wz--n- <6,00g <2,01g

For uses needing  'old'  undecorated human unit simply will continue
to use 'H|h' units.

The new R|r  may further change when we would recongnize some
other way how to improve readability.
2017-01-20 23:52:17 +01:00
Alasdair G Kergon
6a20b22151 devices: Recognise Veritas Dynamic Multipathing
VxDMP doesn't interact very well with udev so always set
  devices/obtain_device_list_from_udev = 0
in lvm.conf on these systems.
2017-01-10 22:23:23 +00:00
Zdenek Kabelac
15e657f110 tests: ignore racy test failure
When test fails here, make it just warning instead of failing whole
test.
2017-01-06 23:39:53 +01:00
Zdenek Kabelac
d757b2431a tests: make test more race immune
Add more delay and increase raid size.
Speedup volume during wait for sync.
Drop --yes from lvcreate.
2017-01-06 23:39:53 +01:00
Zdenek Kabelac
a4be2be5a4 raid: postpone archiving until metadata are changed
Avoid archiving of lvm2 metadata when there is call of 'lvconvert --repair'
on healthy raid LV.
2017-01-06 23:39:04 +01:00
Zdenek Kabelac
0d2a9ebec6 vgchange: also -l is uint32 2017-01-06 21:51:36 +01:00
Zdenek Kabelac
8a93cde75e mirror: relax internal error for a while
With recent commit d6a74025df using
INTERNAL_ERROR while cheking layer LV - it's been noticed mirror
logic currently doesn't do a correct thing during upconversion and
does a full-try instead of checking only allocator capabilities.
This leads to invalid usage of layer.

To keep existing code running before providing a fix, relax
INTERNAL_ERROR just an error and keep the 'code' running.

Once mirror code is fixed, these all check should be switched
to internal errors.
2017-01-06 12:45:07 +01:00
Peter Rajnoha
d90320f4f1 blkdeactivate: also unmount mount point on top of MD device if using blkdeactivate -u
The blkdeactivate script processes MD devices too so we should unmount
any mount point on top of an MD device if blkdeactivate -u|--umount is
called.

Diagnosed and reported by: Rick Warner <rick@microway.com>
See also https://bugzilla.redhat.com/show_bug.cgi?id=1410585.
2017-01-06 11:16:07 +01:00
Zdenek Kabelac
b92a9c3e1a tests: slow down devs for raid more
Since we still experience occasiaonal test failure - slow
things down even more to avoid race.

Add support for 'quick' table changes between normal & delayed tables.
2017-01-05 15:54:14 +01:00
Zdenek Kabelac
c64f4447d9 tests: drop FIXME
Since we fixed core trouble with sequence of
suspend/resume/suspend without udev wait
we can drop 'should' and expect volume is still mounted.
2017-01-05 15:54:14 +01:00
Zdenek Kabelac
74969c9a38 report: report merged state for inactive LV
This was missing piece in 77997c7673.
When merging origin is inactive (while driver is loaded) we
could already report merge in progress values as there is
no way to activate 'old state' now.
2017-01-05 15:54:14 +01:00
Zdenek Kabelac
d6a74025df debug: show proper error message for layer mismatch
Show proper internal error for failing command when there are some
inconsitencies in sizes of LV and its layer instead of rather
meaningless error code 5.

(Could be hit i.e. if user tried to 'resize' cached LV and then
uncache such LV.)
2017-01-05 15:54:14 +01:00
Zdenek Kabelac
3e9c03cbbc cache: resize is still unsupported
During rework of resize code this validation check
has been lost (in my resize branch). Upstream
is still not supporting resize of any cache type LV
so needs to be prevented.
2017-01-05 15:34:22 +01:00
78 changed files with 6104 additions and 12082 deletions

View File

@@ -1,5 +1,10 @@
Version 2.02.169 -
=====================================
Support new internal command _dmeventd_thin_command.
Introduce new dmeventd/thin_command configurable setting.
Use new default units 'r' for displaying sizes.
Also unmount mount point on top of MD device if using blkdeactivate -u.
Restore check preventing resize of cache type volumes (2.02.158).
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.

View File

@@ -1,5 +1,7 @@
Version 1.02.138 -
=====================================
Support configurable command executed from dmeventd thin plugin.
Support new R|r human readable units output format.
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.
Do not try call callback when reverting activation on error path.

View File

@@ -665,7 +665,7 @@ global {
# Configuration option global/units.
# Default value for --units argument.
units = "h"
units = "r"
# Configuration option global/si_unit_consistency.
# Distinguish between powers of 1024 and 1000 bytes.
@@ -1156,7 +1156,8 @@ activation {
# Configuration option activation/missing_stripe_filler.
# Method to fill missing stripes when activating an incomplete LV.
# Using 'error' will make inaccessible parts of the device return I/O
# errors on access. You can instead use a device path, in which case,
# errors on access. Using 'zero' will return success (and zero) on I/O
# You can instead use a device path, in which case,
# that device will be used in place of missing stripes. Using anything
# other than 'error' with mirrored or snapshotted volumes is likely to
# result in data corruption.
@@ -2048,6 +2049,14 @@ dmeventd {
# warning is repeated when 85%, 90% and 95% of the pool is filled.
thin_library = "libdevmapper-event-lvm2thin.so"
# Configuration option dmeventd/thin_command.
# The plugin runs command with each 5% increment when thin-pool data volume
# or metadata volume gets above 50%.
# Command which starts with 'lvm ' prefix is internal lvm command.
# You can write your own handler to customise behaviour in more details.
# This configuration option has an automatic default value.
# thin_command = "lvm lvextend --use-policies"
# Configuration option dmeventd/executable.
# The full path to the dmeventd binary.
# This configuration option has an automatic default value.

View File

@@ -121,6 +121,7 @@ int dmeventd_lvm2_run(const char *cmdline)
int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
const char *cmd, const char *device)
{
static char _internal_prefix[] = "_dmeventd_";
char *vg = NULL, *lv = NULL, *layer;
int r;
@@ -135,6 +136,21 @@ int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
(layer = strstr(lv, "_mlog")))
*layer = '\0';
if (!strncmp(cmd, _internal_prefix, sizeof(_internal_prefix) - 1)) {
dmeventd_lvm2_lock();
/* output of internal command passed via env var */
if (!dmeventd_lvm2_run(cmd))
cmd = NULL;
else if ((cmd = getenv(cmd)))
cmd = dm_pool_strdup(mem, cmd); /* copy with lock */
dmeventd_lvm2_unlock();
if (!cmd) {
log_error("Unable to find configured command.");
return 0;
}
}
r = dm_snprintf(buffer, size, "%s %s/%s", cmd, vg, lv);
dm_pool_free(mem, vg);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2016 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2017 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -40,17 +40,26 @@
#define UMOUNT_COMMAND "/bin/umount"
#define MAX_FAILS (10)
#define MAX_FAILS (256) /* ~42 mins between cmd call retry with 10s delay */
#define THIN_DEBUG 0
struct dso_state {
struct dm_pool *mem;
int metadata_percent_check;
int metadata_percent;
int metadata_warn_once;
int data_percent_check;
int data_percent;
int data_warn_once;
uint64_t known_metadata_size;
uint64_t known_data_size;
unsigned fails;
unsigned max_fails;
int restore_sigset;
sigset_t old_sigset;
pid_t pid;
char **argv;
char cmd_str[1024];
};
@@ -58,259 +67,95 @@ DM_EVENT_LOG_FN("thin")
#define UUID_PREFIX "LVM-"
/* Figure out device UUID has LVM- prefix and is OPEN */
static int _has_unmountable_prefix(int major, int minor)
static int _run_command(struct dso_state *state)
{
struct dm_task *dmt;
struct dm_info info;
const char *uuid;
int r = 0;
char val[3][36];
char *env[] = { val[0], val[1], val[2], NULL };
int i;
if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
return_0;
/* Mark for possible lvm2 command we are running from dmeventd
* lvm2 will not try to talk back to dmeventd while processing it */
(void) dm_snprintf(val[0], sizeof(val[0]), "LVM_RUN_BY_DMEVENTD=1");
if (!dm_task_set_major_minor(dmt, major, minor, 1))
goto_out;
if (state->data_percent) {
/* Prepare some known data to env vars for easy use */
(void) dm_snprintf(val[1], sizeof(val[1]), "DMEVENTD_THIN_POOL_DATA=%d",
state->data_percent / DM_PERCENT_1);
(void) dm_snprintf(val[2], sizeof(val[2]), "DMEVENTD_THIN_POOL_METADATA=%d",
state->metadata_percent / DM_PERCENT_1);
} else {
/* For an error event it's for a user to check status and decide */
env[1] = NULL;
log_debug("Error event processing");
}
if (!dm_task_no_flush(dmt))
stack;
log_verbose("Executing command: %s", state->cmd_str);
if (!dm_task_run(dmt))
goto out;
if (!dm_task_get_info(dmt, &info))
goto out;
if (!info.exists || !info.open_count)
goto out; /* Not open -> not mounted */
if (!(uuid = dm_task_get_uuid(dmt)))
goto out;
/* Check it's public mountable LV
* has prefix LVM- and UUID size is 68 chars */
if (memcmp(uuid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1) ||
strlen(uuid) != 68)
goto out;
#if THIN_DEBUG
log_debug("Found logical volume %s (%u:%u).", uuid, major, minor);
#endif
r = 1;
out:
dm_task_destroy(dmt);
return r;
}
/* Get dependencies for device, and try to find matching device */
static int _has_deps(const char *name, int tp_major, int tp_minor, int *dev_minor)
{
struct dm_task *dmt;
const struct dm_deps *deps;
struct dm_info info;
int major, minor;
int r = 0;
if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
/* TODO:
* Support parallel run of 'task' and it's waitpid maintainence
* ATM we can't handle signaling of SIGALRM
* as signalling is not allowed while 'process_event()' is running
*/
if (!(state->pid = fork())) {
/* child */
(void) close(0);
for (i = 3; i < 255; ++i) (void) close(i);
execve(state->argv[0], state->argv, env);
_exit(errno);
} else if (state->pid == -1) {
log_error("Can't fork command %s.", state->cmd_str);
state->fails = 1;
return 0;
if (!dm_task_set_name(dmt, name))
goto out;
if (!dm_task_no_open_count(dmt))
goto out;
if (!dm_task_run(dmt))
goto out;
if (!dm_task_get_info(dmt, &info))
goto out;
if (!(deps = dm_task_get_deps(dmt)))
goto out;
if (!info.exists || deps->count != 1)
goto out;
major = (int) MAJOR(deps->device[0]);
minor = (int) MINOR(deps->device[0]);
if ((major != tp_major) || (minor != tp_minor))
goto out;
*dev_minor = info.minor;
if (!_has_unmountable_prefix(major, info.minor))
goto out;
#if THIN_DEBUG
{
char dev_name[PATH_MAX];
if (dm_device_get_name(major, minor, 0, dev_name, sizeof(dev_name)))
log_debug("Found %s (%u:%u) depends on %s.",
name, major, *dev_minor, dev_name);
}
#endif
r = 1;
out:
dm_task_destroy(dmt);
return r;
}
/* Get all active devices */
static int _find_all_devs(dm_bitset_t bs, int tp_major, int tp_minor)
{
struct dm_task *dmt;
struct dm_names *names;
unsigned next = 0;
int minor, r = 1;
if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
return 0;
if (!dm_task_run(dmt)) {
r = 0;
goto out;
}
if (!(names = dm_task_get_names(dmt))) {
r = 0;
goto out;
}
if (!names->dev)
goto out;
do {
names = (struct dm_names *)((char *) names + next);
if (_has_deps(names->name, tp_major, tp_minor, &minor))
dm_bit_set(bs, minor);
next = names->next;
} while (next);
out:
dm_task_destroy(dmt);
return r;
}
static int _run(const char *cmd, ...)
{
va_list ap;
int argc = 1; /* for argv[0], i.e. cmd */
int i = 0;
const char **argv;
pid_t pid = fork();
int status;
if (pid == 0) { /* child */
va_start(ap, cmd);
while (va_arg(ap, const char *))
++argc;
va_end(ap);
/* + 1 for the terminating NULL */
argv = alloca(sizeof(const char *) * (argc + 1));
argv[0] = cmd;
va_start(ap, cmd);
while ((argv[++i] = va_arg(ap, const char *)));
va_end(ap);
execvp(cmd, (char **)argv);
log_sys_error("exec", cmd);
exit(127);
}
if (pid > 0) { /* parent */
if (waitpid(pid, &status, 0) != pid)
return 0; /* waitpid failed */
if (!WIFEXITED(status) || WEXITSTATUS(status))
return 0; /* the child failed */
}
if (pid < 0)
return 0; /* fork failed */
return 1; /* all good */
}
struct mountinfo_s {
const char *device;
struct dm_info info;
dm_bitset_t minors; /* Bitset for active thin pool minors */
};
static int _umount_device(char *buffer, unsigned major, unsigned minor,
char *target, void *cb_data)
{
struct mountinfo_s *data = cb_data;
char *words[10];
if ((major == data->info.major) && dm_bit(data->minors, minor)) {
if (dm_split_words(buffer, DM_ARRAY_SIZE(words), 0, words) < DM_ARRAY_SIZE(words))
words[9] = NULL; /* just don't show device name */
log_info("Unmounting thin %s (%d:%d) of thin pool %s (%u:%u) from mount point \"%s\".",
words[9] ? : "", major, minor, data->device,
data->info.major, data->info.minor,
target);
if (!_run(UMOUNT_COMMAND, "-fl", target, NULL))
log_error("Failed to lazy umount thin %s (%d:%d) from %s: %s.",
words[9], major, minor, target, strerror(errno));
}
return 1;
}
/*
* Find all thin pool LV users and try to umount them.
* TODO: work with read-only thin pool support
*/
static void _umount(struct dm_task *dmt)
{
/* TODO: Convert to use hash to reduce memory usage */
static const size_t MINORS = (1U << 20); /* 20 bit */
struct mountinfo_s data = { NULL };
if (!dm_task_get_info(dmt, &data.info))
return;
data.device = dm_task_get_name(dmt);
if (!(data.minors = dm_bitset_create(NULL, MINORS))) {
log_error("Failed to allocate bitset. Not unmounting %s.", data.device);
goto out;
}
if (!_find_all_devs(data.minors, data.info.major, data.info.minor)) {
log_error("Failed to detect mounted volumes for %s.", data.device);
goto out;
}
if (!dm_mountinfo_read(_umount_device, &data)) {
log_error("Could not parse mountinfo file.");
goto out;
}
out:
if (data.minors)
dm_bitset_destroy(data.minors);
}
static int _use_policy(struct dm_task *dmt, struct dso_state *state)
{
#if THIN_DEBUG
log_debug("dmeventd executes: %s.", state->cmd_str);
#endif
if (state->argv)
return _run_command(state);
if (!dmeventd_lvm2_run_with_lock(state->cmd_str)) {
log_error("Failed to extend thin pool %s.",
dm_task_get_name(dmt));
state->fails++;
log_error("Failed command for %s.", dm_task_get_name(dmt));
state->fails = 1;
return 0;
}
state->fails = 0;
return 1;
}
/* Check if executed command has finished
* Only 1 command may run */
static int _wait_for_pid(struct dso_state *state)
{
int status = 0;
if (state->pid == -1)
return 1;
if (!waitpid(state->pid, &status, WNOHANG))
return 0;
/* Wait for finish */
if (WIFEXITED(status)) {
log_verbose("Child %d exited with status %d.",
state->pid, WEXITSTATUS(status));
state->fails = WEXITSTATUS(status) ? 1 : 0;
} else {
if (WIFSIGNALED(status))
log_verbose("Child %d was terminated with status %d.",
state->pid, WTERMSIG(status));
state->fails = 1;
}
state->pid = -1;
return 1;
}
@@ -319,7 +164,6 @@ void process_event(struct dm_task *dmt,
void **user)
{
const char *device = dm_task_get_name(dmt);
int percent;
struct dso_state *state = *user;
struct dm_status_thin_pool *tps = NULL;
void *next = NULL;
@@ -327,7 +171,6 @@ void process_event(struct dm_task *dmt,
char *target_type = NULL;
char *params;
int needs_policy = 0;
int needs_umount = 0;
struct dm_task *new_dmt = NULL;
#if THIN_DEBUG
@@ -335,14 +178,15 @@ void process_event(struct dm_task *dmt,
dm_percent_to_float(state->data_percent_check),
dm_percent_to_float(state->metadata_percent_check));
#endif
#if 0
/* No longer monitoring, waiting for remove */
if (!state->meta_percent_check && !state->data_percent_check)
if (!_wait_for_pid(state)) {
log_warn("WARNING: Skipping event, child %d is still running (%s).",
state->pid, state->cmd_str);
return;
#endif
}
if (event & DM_EVENT_DEVICE_ERROR) {
/* Error -> no need to check and do instant resize */
state->data_percent = state->metadata_percent = 0;
if (_use_policy(dmt, state))
goto out;
@@ -380,7 +224,6 @@ void process_event(struct dm_task *dmt,
if (!dm_get_status_thin_pool(state->mem, params, &tps)) {
log_error("Failed to parse status.");
needs_umount = 1;
goto out;
}
@@ -395,72 +238,114 @@ void process_event(struct dm_task *dmt,
if (state->known_metadata_size != tps->total_metadata_blocks) {
state->metadata_percent_check = CHECK_MINIMUM;
state->known_metadata_size = tps->total_metadata_blocks;
state->fails = 0;
}
if (state->known_data_size != tps->total_data_blocks) {
state->data_percent_check = CHECK_MINIMUM;
state->known_data_size = tps->total_data_blocks;
state->fails = 0;
}
percent = dm_make_percent(tps->used_metadata_blocks, tps->total_metadata_blocks);
if (percent >= state->metadata_percent_check) {
/*
* Usage has raised more than CHECK_STEP since the last
* time. Run actions.
*/
state->metadata_percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
/*
* Trigger action when threshold boundary is exceeded.
* Report 80% threshold warning when it's used above 80%.
* Only 100% is exception as it cannot be surpased so policy
* action is called for: >50%, >55% ... >95%, 100%
*/
state->metadata_percent = dm_make_percent(tps->used_metadata_blocks, tps->total_metadata_blocks);
if (state->metadata_percent <= WARNING_THRESH)
state->metadata_warn_once = 0; /* Dropped bellow threshold, reset warn once */
else if (!state->metadata_warn_once++) /* Warn once when raised above threshold */
log_warn("WARNING: Thin pool %s metadata is now %.2f%% full.",
device, dm_percent_to_float(state->metadata_percent));
if (state->metadata_percent > CHECK_MINIMUM) {
/* Run action when usage raised more than CHECK_STEP since the last time */
if (state->metadata_percent > state->metadata_percent_check)
needs_policy = 1;
state->metadata_percent_check = (state->metadata_percent / CHECK_STEP + 1) * CHECK_STEP;
if (state->metadata_percent_check == DM_PERCENT_100)
state->metadata_percent_check--; /* Can't get bigger then 100% */
} else
state->metadata_percent_check = CHECK_MINIMUM;
/* FIXME: extension of metadata needs to be written! */
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
log_warn("WARNING: Thin pool %s metadata is now %.2f%% full.",
device, dm_percent_to_float(percent));
needs_policy = 1;
state->data_percent = dm_make_percent(tps->used_data_blocks, tps->total_data_blocks);
if (state->data_percent <= WARNING_THRESH)
state->data_warn_once = 0;
else if (!state->data_warn_once++)
log_warn("WARNING: Thin pool %s data is now %.2f%% full.",
device, dm_percent_to_float(state->data_percent));
if (state->data_percent > CHECK_MINIMUM) {
/* Run action when usage raised more than CHECK_STEP since the last time */
if (state->data_percent > state->data_percent_check)
needs_policy = 1;
state->data_percent_check = (state->data_percent / CHECK_STEP + 1) * CHECK_STEP;
if (state->data_percent_check == DM_PERCENT_100)
state->data_percent_check--; /* Can't get bigger then 100% */
} else
state->data_percent_check = CHECK_MINIMUM;
if (percent >= UMOUNT_THRESH)
needs_umount = 1;
}
/* Reduce number of _use_policy() calls by power-of-2 factor till frequency of MAX_FAILS is reached.
* Avoids too high number of error retries, yet shows some status messages in log regularly.
* i.e. PV could have been pvmoved and VG/LV was locked for a while...
*/
if (state->fails) {
if (state->fails++ <= state->max_fails) {
log_debug("Postponing frequently failing policy (%u <= %u).",
state->fails - 1, state->max_fails);
return;
}
if (state->max_fails < MAX_FAILS)
state->max_fails <<= 1;
state->fails = needs_policy = 1; /* Retry failing command */
} else
state->max_fails = 1; /* Reset on success */
percent = dm_make_percent(tps->used_data_blocks, tps->total_data_blocks);
if (percent >= state->data_percent_check) {
/*
* Usage has raised more than CHECK_STEP since
* the last time. Run actions.
*/
state->data_percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
log_warn("WARNING: Thin pool %s data is now %.2f%% full.",
device, dm_percent_to_float(percent));
needs_policy = 1;
if (percent >= UMOUNT_THRESH)
needs_umount = 1;
}
if (needs_policy &&
_use_policy(dmt, state))
needs_umount = 0; /* No umount when command was successful */
if (needs_policy)
_use_policy(dmt, state);
out:
if (needs_umount) {
_umount(dmt);
/* Until something changes, do not retry any more actions */
state->data_percent_check = state->metadata_percent_check = (DM_PERCENT_1 * 101);
}
if (tps)
dm_pool_free(state->mem, tps);
if (state->fails >= MAX_FAILS) {
log_warn("WARNING: Dropping monitoring of %s. "
"lvm2 command fails too often (%u times in row).",
device, state->fails);
pthread_kill(pthread_self(), SIGALRM);
}
if (new_dmt)
dm_task_destroy(new_dmt);
}
/* Handle SIGCHLD for a thread */
static void _sig_child(int signum __attribute__((unused)))
{
/* empty SIG_IGN */;
}
/* Setup handler for SIGCHLD when executing external command
* to get quick 'waitpid()' reaction
* It will interrupt syscall just like SIGALRM and
* invoke process_event().
*/
static void _init_thread_signals(struct dso_state *state)
{
struct sigaction act = { .sa_handler = _sig_child };
sigset_t my_sigset;
sigemptyset(&my_sigset);
if (sigaction(SIGCHLD, &act, NULL))
log_warn("WARNING: Failed to set SIGCHLD action.");
else if (sigaddset(&my_sigset, SIGCHLD))
log_warn("WARNING: Failed to add SIGCHLD to set.");
else if (pthread_sigmask(SIG_UNBLOCK, &my_sigset, &state->old_sigset))
log_warn("WARNING: Failed to unblock SIGCHLD.");
else
state->restore_sigset = 1;
}
static void _restore_thread_signals(struct dso_state *state)
{
if (state->restore_sigset &&
pthread_sigmask(SIG_SETMASK, &state->old_sigset, NULL))
log_warn("WARNING: Failed to block SIGCHLD.");
}
int register_device(const char *device,
const char *uuid __attribute__((unused)),
int major __attribute__((unused)),
@@ -468,20 +353,36 @@ int register_device(const char *device,
void **user)
{
struct dso_state *state;
int maxcmd;
char *str;
if (!dmeventd_lvm2_init_with_pool("thin_pool_state", state))
goto_bad;
if (!dmeventd_lvm2_command(state->mem, state->cmd_str,
sizeof(state->cmd_str),
"lvextend --use-policies",
device)) {
"_dmeventd_thin_command", device)) {
dmeventd_lvm2_exit_with_pool(state);
goto_bad;
}
state->metadata_percent_check = CHECK_MINIMUM;
state->data_percent_check = CHECK_MINIMUM;
if (strncmp(state->cmd_str, "lvm ", 4)) {
maxcmd = 2; /* space for last NULL element */
for (str = state->cmd_str; *str; str++)
if (*str == ' ')
maxcmd++;
if (!(str = dm_pool_strdup(state->mem, state->cmd_str)) ||
!(state->argv = dm_pool_zalloc(state->mem, maxcmd * sizeof(char *)))) {
log_error("Failed to allocate memory for command.");
goto bad;
}
dm_split_words(str, maxcmd - 1, 0, state->argv);
_init_thread_signals(state);
} else
memmove(state->cmd_str, state->cmd_str + 4, strlen(state->cmd_str + 4) + 1);
state->pid = -1;
*user = state;
log_info("Monitoring thin pool %s.", device);
@@ -500,6 +401,28 @@ int unregister_device(const char *device,
void **user)
{
struct dso_state *state = *user;
int i;
for (i = 0; !_wait_for_pid(state) && (i < 6); ++i) {
if (i == 0)
/* Give it 2 seconds, then try to terminate & kill it */
log_verbose("Child %d still not finished (%s) waiting.",
state->pid, state->cmd_str);
else if (i == 3) {
log_warn("WARNING: Terminating child %d.", state->pid);
kill(state->pid, SIGINT);
kill(state->pid, SIGTERM);
} else if (i == 5) {
log_warn("WARNING: Killing child %d.", state->pid);
kill(state->pid, SIGKILL);
}
sleep(1);
}
if (state->pid != -1)
log_warn("WARNING: Cannot kill child %d!", state->pid);
_restore_thread_signals(state);
dmeventd_lvm2_exit_with_pool(state);
log_info("No longer monitoring thin pool %s.", device);

View File

@@ -192,6 +192,9 @@ static int _get_env_vars(struct cmd_context *cmd)
}
}
if (strcmp((getenv("LVM_RUN_BY_DMEVENTD") ? : "0"), "1") == 0)
init_run_by_dmeventd(cmd);
return 1;
}
@@ -1755,6 +1758,15 @@ bad:
return 0;
}
int init_run_by_dmeventd(struct cmd_context *cmd)
{
init_dmeventd_monitor(DMEVENTD_MONITOR_IGNORE);
init_ignore_suspended_devices(1);
init_disable_dmeventd_monitoring(1); /* Lock settings */
return 0;
}
void destroy_config_context(struct cmd_context *cmd)
{
_destroy_config(cmd);

View File

@@ -88,19 +88,11 @@ struct cmd_context {
* Command line and arguments.
*/
const char *cmd_line;
const char *name; /* needed before cmd->command is set */
struct command *command;
char **argv;
struct arg_values *opt_arg_values;
struct arg_values *arg_values;
struct dm_list arg_value_groups;
/*
* Position args remaining after command name
* and --options are removed from original argc/argv.
*/
int position_argc;
char **position_argv;
/*
* Format handlers.
*/
@@ -241,6 +233,7 @@ int config_files_changed(struct cmd_context *cmd);
int init_lvmcache_orphans(struct cmd_context *cmd);
int init_filters(struct cmd_context *cmd, unsigned load_persistent_cache);
int init_connections(struct cmd_context *cmd);
int init_run_by_dmeventd(struct cmd_context *cmd);
/*
* A config context is a very light weight cmd struct that

View File

@@ -1859,6 +1859,12 @@ cfg(dmeventd_thin_library_CFG, "thin_library", dmeventd_CFG_SECTION, 0, CFG_TYPE
"and emits a warning through syslog when the usage exceeds 80%. The\n"
"warning is repeated when 85%, 90% and 95% of the pool is filled.\n")
cfg(dmeventd_thin_command_CFG, "thin_command", dmeventd_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_DMEVENTD_THIN_COMMAND, vsn(2, 2, 169), NULL, 0, NULL,
"The plugin runs command with each 5% increment when thin-pool data volume\n"
"or metadata volume gets above 50%.\n"
"Command which starts with 'lvm ' prefix is internal lvm command.\n"
"You can write your own handler to customise behaviour in more details.\n")
cfg(dmeventd_executable_CFG, "executable", dmeventd_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_DMEVENTD_PATH, vsn(2, 2, 73), "@DMEVENTD_PATH@", 0, NULL,
"The full path to the dmeventd binary.\n")

View File

@@ -81,6 +81,7 @@
#define DEFAULT_DMEVENTD_MIRROR_LIB "libdevmapper-event-lvm2mirror.so"
#define DEFAULT_DMEVENTD_SNAPSHOT_LIB "libdevmapper-event-lvm2snapshot.so"
#define DEFAULT_DMEVENTD_THIN_LIB "libdevmapper-event-lvm2thin.so"
#define DEFAULT_DMEVENTD_THIN_COMMAND "lvm lvextend --use-policies"
#define DEFAULT_DMEVENTD_MONITOR 1
#define DEFAULT_BACKGROUND_POLLING 1
@@ -176,7 +177,7 @@
#define DEFAULT_INDENT 1
#define DEFAULT_ABORT_ON_INTERNAL_ERRORS 0
#define DEFAULT_DETECT_INTERNAL_VG_CACHE_CORRUPTION 0
#define DEFAULT_UNITS "h"
#define DEFAULT_UNITS "r"
#define DEFAULT_SUFFIX 1
#define DEFAULT_HOSTTAGS 0

View File

@@ -125,6 +125,10 @@ struct dev_types *create_dev_types(const char *proc_dir,
if (!strncmp("emcpower", line + i, 8) && isspace(*(line + i + 8)))
dt->emcpower_major = line_maj;
/* Look for Veritas Dynamic Multipathing */
if (!strncmp("VxDMP", line + i, 5) && isspace(*(line + i + 5)))
dt->vxdmp_major = line_maj;
if (!strncmp("loop", line + i, 4) && isspace(*(line + i + 4)))
dt->loop_major = line_maj;
@@ -218,6 +222,9 @@ int dev_subsystem_part_major(struct dev_types *dt, struct device *dev)
if (MAJOR(dev->dev) == dt->power2_major)
return 1;
if (MAJOR(dev->dev) == dt->vxdmp_major)
return 1;
if ((MAJOR(dev->dev) == dt->blkext_major) &&
dev_get_primary_dev(dt, dev, &primary_dev) &&
(MAJOR(primary_dev) == dt->md_major))
@@ -246,6 +253,9 @@ const char *dev_subsystem_name(struct dev_types *dt, struct device *dev)
if (MAJOR(dev->dev) == dt->power2_major)
return "POWER2";
if (MAJOR(dev->dev) == dt->vxdmp_major)
return "VXDMP";
if (MAJOR(dev->dev) == dt->blkext_major)
return "BLKEXT";

View File

@@ -41,6 +41,7 @@ struct dev_types {
int drbd_major;
int device_mapper_major;
int emcpower_major;
int vxdmp_major;
int power2_major;
int dasd_major;
int loop_major;

View File

@@ -63,5 +63,6 @@ static const dev_known_type_t _dev_known_types[] = {
{"bcache", 1, "bcache block device cache"},
{"nvme", 64, "NVM Express"},
{"zvol", 16, "ZFS Zvols"},
{"VxDMP", 16, "Veritas Dynamic Multipathing"},
{"", 0, ""}
};

View File

@@ -319,6 +319,7 @@ static int _lv_layout_and_role_thin(struct dm_pool *mem,
{
int top_level = 0;
unsigned snap_count;
struct lv_segment *seg;
/* non-top-level LVs */
if (lv_is_thin_pool_metadata(lv)) {
@@ -352,7 +353,7 @@ static int _lv_layout_and_role_thin(struct dm_pool *mem,
!str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_MULTITHINORIGIN]))
goto_bad;
}
if (lv_is_thin_snapshot(lv))
if ((seg = first_seg(lv)) && (seg->origin || seg->external_lv))
if (!str_list_add(mem, role, _lv_type_names[LV_TYPE_SNAPSHOT]) ||
!str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_THINSNAPSHOT]))
goto_bad;
@@ -4686,6 +4687,11 @@ static int _lvresize_check(struct logical_volume *lv,
return 0;
}
if (lv_is_cache_type(lv)) {
log_error("Unable to resize logical volumes of cache type.");
return 0;
}
if (!lv_is_visible(lv) &&
!lv_is_thin_pool_metadata(lv) &&
!lv_is_lockd_sanlock_lv(lv)) {
@@ -6527,12 +6533,43 @@ int remove_layer_from_lv(struct logical_volume *lv,
* Before removal, the layer should be cleaned up,
* i.e. additional segments and areas should have been removed.
*/
if (dm_list_size(&parent_lv->segments) != 1 ||
parent_seg->area_count != 1 ||
seg_type(parent_seg, 0) != AREA_LV ||
layer_lv != seg_lv(parent_seg, 0) ||
parent_lv->le_count != layer_lv->le_count)
return_0;
/* FIXME:
* These are all INTERNAL_ERROR, but ATM there is
* some internal API problem and this code is wrongle
* executed with certain mirror manipulations.
* So we need to fix mirror code first, then switch...
*/
if (dm_list_size(&parent_lv->segments) != 1) {
log_error("Invalid %d segments in %s, expected only 1.",
dm_list_size(&parent_lv->segments),
display_lvname(parent_lv));
return 0;
}
if (parent_seg->area_count != 1) {
log_error("Invalid %d area count(s) in %s, expected only 1.",
parent_seg->area_count, display_lvname(parent_lv));
return 0;
}
if (seg_type(parent_seg, 0) != AREA_LV) {
log_error("Invalid seg_type %d in %s, expected LV.",
seg_type(parent_seg, 0), display_lvname(parent_lv));
return 0;
}
if (layer_lv != seg_lv(parent_seg, 0)) {
log_error("Layer doesn't match segment in %s.",
display_lvname(parent_lv));
return 0;
}
if (parent_lv->le_count != layer_lv->le_count) {
log_error("Inconsistent extent count (%u != %u) of layer %s.",
parent_lv->le_count, layer_lv->le_count,
display_lvname(parent_lv));
return 0;
}
if (!lv_empty(parent_lv))
return_0;

View File

@@ -1067,16 +1067,9 @@ struct lv_segment *get_only_segment_using_this_lv(const struct logical_volume *l
* Useful functions for managing snapshots.
*/
int lv_is_origin(const struct logical_volume *lv);
#define lv_is_thick_origin lv_is_origin
int lv_is_thin_origin(const struct logical_volume *lv, unsigned *snap_count);
int lv_is_thin_snapshot(const struct logical_volume *lv);
int lv_is_cow(const struct logical_volume *lv);
#define lv_is_thick_snapshot lv_is_cow
int lv_is_cache_origin(const struct logical_volume *lv);
int lv_is_cow(const struct logical_volume *lv);
int lv_is_merging_cow(const struct logical_volume *cow);
uint32_t cow_max_extents(const struct logical_volume *origin, uint32_t chunk_size);
int cow_has_min_chunks(const struct volume_group *vg, uint32_t cow_extents, uint32_t chunk_size);

View File

@@ -5629,11 +5629,6 @@ static int _access_vg_lock_type(struct cmd_context *cmd, struct volume_group *vg
}
}
if (test_mode()) {
log_error("Test mode is not yet supported with lock type %s.", vg->lock_type);
return 0;
}
return 1;
}

View File

@@ -3952,9 +3952,6 @@ static int _lv_raid_rebuild_or_replace(struct logical_volume *lv,
return 0;
}
if (!archive(lv->vg))
return_0;
/*
* How many sub-LVs are being removed?
*/
@@ -3972,6 +3969,9 @@ static int _lv_raid_rebuild_or_replace(struct logical_volume *lv,
lv_is_on_pvs(seg_metalv(raid_seg, s), remove_pvs)) {
match_count++;
if (rebuild) {
if ((match_count == 1) &&
!archive(lv->vg))
return_0;
seg_lv(raid_seg, s)->status |= LV_REBUILD;
seg_metalv(raid_seg, s)->status |= LV_REBUILD;
}
@@ -4017,6 +4017,9 @@ static int _lv_raid_rebuild_or_replace(struct logical_volume *lv,
if (rebuild)
goto skip_alloc;
if (!archive(lv->vg))
return_0;
/* Prevent any PVs holding image components from being used for allocation */
if (!_avoid_pvs_with_other_images_of_lv(lv, allocate_pvs)) {
log_error("Failed to prevent PVs holding image components "

View File

@@ -752,19 +752,6 @@ int lv_is_thin_origin(const struct logical_volume *lv, unsigned int *snap_count)
return r;
}
int lv_is_thin_snapshot(const struct logical_volume *lv)
{
struct lv_segment *seg;
if (!lv_is_thin_volume(lv))
return 0;
if ((seg = first_seg(lv)) && (seg->origin || seg->external_lv))
return 1;
return 0;
}
/*
* Explict check of new thin pool for usability
*

View File

@@ -1,4 +1,5 @@
dm_bit_get_last
dm_bit_get_prev
dm_stats_update_regions_from_fd
dm_bitset_parse_list
dm_stats_bind_from_fd

View File

@@ -1320,8 +1320,9 @@ int dm_stats_get_group_descriptor(const struct dm_stats *dms,
* On success the function returns a pointer to an array of uint64_t
* containing the IDs of the newly created regions. The region_id
* array is terminated by the value DM_STATS_REGION_NOT_PRESENT and
* should be freed using dm_free() when no longer required. On error
* NULL is returned.
* should be freed using dm_free() when no longer required.
*
* On error NULL is returned.
*
* Following a call to dm_stats_create_regions_from_fd() the handle
* is guaranteed to be in a listed state, and to contain any region
@@ -1329,12 +1330,43 @@ int dm_stats_get_group_descriptor(const struct dm_stats *dms,
*
* The group_id for the new group is equal to the region_id value in
* the first array element.
*
*/
uint64_t *dm_stats_create_regions_from_fd(struct dm_stats *dms, int fd,
int group, int precise,
struct dm_histogram *bounds,
const char *alias);
/*
* Update a group of regions that correspond to the extents of a file
* in the filesystem, adding and removing regions to account for
* allocation changes in the underlying file.
*
* File descriptor fd must reference a regular file, open for reading,
* in a local file system that supports the FIEMAP ioctl, and that
* returns data describing the physical location of extents.
*
* The file descriptor can be closed by the caller following the call
* to dm_stats_update_regions_from_fd().
*
* On success the function returns a pointer to an array of uint64_t
* containing the IDs of the updated regions (including any existing
* regions that were not modified by the call).
*
* The region_id array is terminated by the special value
* DM_STATS_REGION_NOT_PRESENT and should be freed using dm_free()
* when no longer required.
*
* On error NULL is returned.
*
* Following a call to dm_stats_update_regions_from_fd() the handle
* is guaranteed to be in a listed state, and to contain any region
* and group identifiers created by the operation.
*
* This function cannot be used with file mapped regions that are
* not members of a group: either group the regions, or remove them
* and re-map them with dm_stats_create_regions_from_fd().
*/
uint64_t *dm_stats_update_regions_from_fd(struct dm_stats *dms, int fd,
uint64_t group_id);
/*
* Call this to actually run the ioctl.

View File

@@ -261,6 +261,9 @@ static int _stats_group_id_present(const struct dm_stats *dms, uint64_t id)
{
struct dm_stats_group *group = NULL;
if (id == DM_STATS_GROUP_NOT_PRESENT)
return 0;
if (!dms || !dms->regions)
return_0;
@@ -3865,6 +3868,37 @@ static int _extent_start_compare(const void *p1, const void *p2)
return 1;
}
/*
* Resize the group bitmap corresponding to group_id so that it can
* contain at least num_regions members.
*/
static int _stats_resize_group(struct dm_stats_group *group, int num_regions)
{
int last_bit = dm_bit_get_last(group->regions);
dm_bitset_t new, old;
if (last_bit >= num_regions) {
log_error("Cannot resize group bitmap to %d with bit %d set.",
num_regions, last_bit);
return 0;
}
log_very_verbose("Resizing group bitmap from %d to %d (last_bit: %d).",
group->regions[0], num_regions, last_bit);
new = dm_bitset_create(NULL, num_regions);
if (!new) {
log_error("Could not allocate memory for new group bitmap.");
return 0;
}
old = group->regions;
dm_bit_copy(new, old);
group->regions = new;
dm_bitset_destroy(old);
return 1;
}
static int _stats_create_group(struct dm_stats *dms, dm_bitset_t regions,
const char *alias, uint64_t *group_id)
{
@@ -4218,8 +4252,8 @@ bad:
return 0;
}
static int _stats_add_extent(struct dm_pool *mem, struct fiemap_extent *fm_ext,
uint64_t id)
static int _stats_add_file_extent(int fd, struct dm_pool *mem, uint64_t id,
struct fiemap_extent *fm_ext)
{
struct _extent extent;
@@ -4229,16 +4263,17 @@ static int _stats_add_extent(struct dm_pool *mem, struct fiemap_extent *fm_ext,
/* convert bytes to dm (512b) sectors */
extent.start = fm_ext->fe_physical >> SECTOR_SHIFT;
extent.len = fm_ext->fe_length >> SECTOR_SHIFT;
extent.id = id;
log_very_verbose("Extent " FMTu64 " on fd %d at " FMTu64 "+"
FMTu64, extent.id, fd, extent.start, extent.len);
if (!dm_pool_grow_object(mem, &extent,
sizeof(extent))) {
log_error("Cannot map file: failed to grow extent map.");
return 0;
}
return 1;
}
/* test for the boundary of an extent */
@@ -4255,7 +4290,7 @@ do { \
*(to) = *(from); \
} while (0)
static uint64_t _stats_map_extents(struct dm_pool *mem,
static uint64_t _stats_map_extents(int fd, struct dm_pool *mem,
struct fiemap *fiemap,
struct fiemap_extent *fm_ext,
struct fiemap_extent *fm_last,
@@ -4286,16 +4321,34 @@ static uint64_t _stats_map_extents(struct dm_pool *mem,
& (FIEMAP_EXTENT_UNKNOWN | FIEMAP_EXTENT_DELALLOC))
continue;
if (ext_boundary(fm_ext[i], expected)) {
if (!_stats_add_extent(mem, fm_pending, nr_extents))
/*
* Begin a new extent if the current physical address differs
* from the expected address yielded by fm_last.fe_physical +
* fm_last.fe_length.
*
* A logical discontinuity is seen at the start of the file if
* unwritten space exists before the first extent: do not add
* any extent record until we have accumulated a non-zero length
* in fm_pending.
*/
if (fm_pending->fe_length &&
ext_boundary(fm_ext[i], expected)) {
if (!_stats_add_file_extent(fd, mem, nr_extents,
fm_pending))
goto_bad;
nr_extents++;
/* Begin a new pending extent. */
ext_copy(fm_pending, fm_ext + i);
} else {
expected = 0;
/* Begin a new pending extent for extent 0. */
if (fm_ext[i].fe_logical == 0)
/* Begin a new pending extent for extent 0. If there is
* a hole at the start of the file, the first allocated
* extent will have a non-zero fe_logical. Detect this
* case by testing fm_pending->fe_length: if no length
* has been accumulated we are handling the first
* physical extent of the file.
*/
if (!fm_pending->fe_length || fm_ext[i].fe_logical == 0)
ext_copy(fm_pending, fm_ext + i);
else
/* accumulate this logical extent's length */
@@ -4308,8 +4361,8 @@ static uint64_t _stats_map_extents(struct dm_pool *mem,
* If the file only has a single extent, no boundary is ever
* detected to trigger addition of the first extent.
*/
if (fm_ext[i - 1].fe_logical == 0) {
_stats_add_extent(mem, fm_pending, nr_extents);
if (*eof || (fm_ext[i - 1].fe_logical == 0)) {
_stats_add_file_extent(fd, mem, nr_extents, fm_pending);
nr_extents++;
}
@@ -4341,7 +4394,6 @@ static struct _extent *_stats_get_extents_for_file(struct dm_pool *mem, int fd,
struct _extent *extents;
unsigned long flags = 0;
uint64_t *buf;
int rc;
buf = dm_zalloc(STATS_FIE_BUF_LEN);
if (!buf) {
@@ -4361,7 +4413,7 @@ static struct _extent *_stats_get_extents_for_file(struct dm_pool *mem, int fd,
if (!dm_pool_begin_object(mem, sizeof(*extents)))
return NULL;
flags |= FIEMAP_FLAG_SYNC;
flags = FIEMAP_FLAG_SYNC;
do {
/* start of ioctl loop - zero size and set count to bufsize */
@@ -4370,10 +4422,8 @@ static struct _extent *_stats_get_extents_for_file(struct dm_pool *mem, int fd,
fiemap->fm_extent_count = *count;
/* get count-sized chunk of extents */
rc = ioctl(fd, FS_IOC_FIEMAP, (unsigned long) fiemap);
if (rc < 0) {
rc = -errno;
if (rc == -EBADR)
if (ioctl(fd, FS_IOC_FIEMAP, (unsigned long) fiemap) < 0) {
if (errno == EBADR)
log_err_once("FIEMAP failed with unknown "
"flags %x.", fiemap->fm_flags);
goto bad;
@@ -4383,8 +4433,9 @@ static struct _extent *_stats_get_extents_for_file(struct dm_pool *mem, int fd,
if (fiemap->fm_mapped_extents == 0)
break;
nr_extents += _stats_map_extents(mem, fiemap, fm_ext, &fm_last,
&fm_pending, nr_extents, &eof);
nr_extents += _stats_map_extents(fd, mem, fiemap, fm_ext,
&fm_last, &fm_pending,
nr_extents, &eof);
/* check for extent mapping error */
if (eof < 0)
@@ -4412,23 +4463,140 @@ bad:
return NULL;
}
#define MATCH_EXTENT(e, s, l) \
(((e).start == (s)) && ((e).len == (l)))
static struct _extent *_find_extent(size_t nr_extents, struct _extent *extents,
uint64_t start, uint64_t len)
{
size_t i;
for (i = 0; i < nr_extents; i++)
if (MATCH_EXTENT(extents[i], start, len))
return extents + i;
return NULL;
}
/*
* Create a set of regions representing the extents of a file and
* return a table of uint64_t region_id values. The number of regions
* Clean up a table of region_id values that were created during a
* failed dm_stats_create_regions_from_fd, or dm_stats_update_regions_from_fd
* operation.
*/
static void _stats_cleanup_region_ids(struct dm_stats *dms, uint64_t *regions,
uint64_t nr_regions)
{
uint64_t i;
for (i = 0; i < nr_regions; i++)
if (!_stats_delete_region(dms, regions[i]))
log_error("Could not delete region " FMTu64 ".", i);
}
/*
* First update pass: prune no-longer-allocated extents from the group
* and build a table of the remaining extents so that their creation
* can be skipped in the second pass.
*/
static int _stats_unmap_regions(struct dm_stats *dms, uint64_t group_id,
struct dm_pool *mem, struct _extent *extents,
struct _extent **old_extents, uint64_t *count,
int *regroup)
{
struct dm_stats_region *region = NULL;
struct dm_stats_group *group = NULL;
int64_t nr_kept, nr_old, i;
struct _extent ext;
group = &dms->groups[group_id];
log_very_verbose("Checking for changed file extents in group ID "
FMTu64, group_id);
if (!dm_pool_begin_object(mem, sizeof(**old_extents))) {
log_error("Could not allocate extent table.");
return 0;
}
nr_kept = nr_old = 0; /* counts of old and retained extents */
/*
* First pass: delete de-allocated extents and set regroup=1 if
* deleting the current group leader.
*/
i = dm_bit_get_last(group->regions);
for (; i >= 0; i = dm_bit_get_prev(group->regions, i)) {
region = &dms->regions[i];
nr_old++;
if (_find_extent(*count, extents,
region->start, region->len)) {
ext.start = region->start;
ext.len = region->len;
ext.id = i;
nr_kept++;
dm_pool_grow_object(mem, &ext,
sizeof(ext));
log_very_verbose("Kept region " FMTu64, i);
} else {
if (i == group_id)
*regroup = 1;
if (!_stats_delete_region(dms, i)) {
log_error("Could not remove region ID " FMTu64,
i);
goto out;
}
log_very_verbose("Deleted region " FMTu64, i);
}
}
*old_extents = dm_pool_end_object(mem);
if (!*old_extents) {
log_error("Could not finalize region extent table.");
goto out;
}
log_very_verbose("Kept %ld of %ld old extents",
nr_kept, nr_old);
log_very_verbose("Found " FMTu64 " new extents",
*count - nr_kept);
return nr_kept;
out:
dm_pool_abandon_object(mem);
return -1;
}
/*
* Create or update a set of regions representing the extents of a file
* and return a table of uint64_t region_id values. The number of regions
* created is returned in the memory pointed to by count (which must be
* non-NULL).
*
* If group_id is not equal to DM_STATS_GROUP_NOT_PRESENT, it is assumed
* that group_id corresponds to a group containing existing regions that
* were mapped to this file at an earlier time: regions will be added or
* removed to reflect the current status of the file.
*/
static uint64_t *_stats_create_file_regions(struct dm_stats *dms, int fd,
struct dm_histogram *bounds,
int precise, uint64_t *count)
static uint64_t *_stats_map_file_regions(struct dm_stats *dms, int fd,
struct dm_histogram *bounds,
int precise, uint64_t group_id,
uint64_t *count, int *regroup)
{
uint64_t *regions = NULL, i, fail_region;
struct _extent *extents = NULL, *old_extents;
uint64_t *regions = NULL, fail_region;
struct dm_stats_group *group = NULL;
struct dm_pool *extent_mem = NULL;
struct _extent *extents = NULL;
struct _extent *old_ext;
char *hist_arg = NULL;
int update, num_bits;
struct statfs fsbuf;
int64_t nr_kept, i;
struct stat buf;
update = _stats_group_id_present(dms, group_id);
#ifdef BTRFS_SUPER_MAGIC
if (fstatfs(fd, &fsbuf)) {
log_error("fstatfs failed for fd %d", fd);
@@ -4457,6 +4625,18 @@ static uint64_t *_stats_create_file_regions(struct dm_stats *dms, int fd,
return 0;
}
/*
* If regroup is set here, we are creating a new filemap: otherwise
* we are updating a group with a valid group identifier in group_id.
*/
if (update)
log_very_verbose("Updating extents from fd %d with group ID "
FMTu64 " on (%d:%d)", fd, group_id,
major(buf.st_dev), minor(buf.st_dev));
else
log_very_verbose("Mapping extents from fd %d on (%d:%d)",
fd, major(buf.st_dev), minor(buf.st_dev));
/* Use a temporary, private pool for the extent table. This avoids
* hijacking the dms->mem (region table) pool which would lead to
* interleaving temporary allocations with dm_stats_list() data,
@@ -4470,19 +4650,41 @@ static uint64_t *_stats_create_file_regions(struct dm_stats *dms, int fd,
return_0;
}
if (bounds) {
/* _build_histogram_arg enables precise if vals < 1ms. */
if (update) {
group = &dms->groups[group_id];
if ((nr_kept = _stats_unmap_regions(dms, group_id, extent_mem,
extents, &old_extents,
count, regroup)) < 0)
goto_out;
}
if (bounds)
if (!(hist_arg = _build_histogram_arg(bounds, &precise)))
goto_out;
}
/* make space for end-of-table marker */
if (!(regions = dm_malloc((1 + *count) * sizeof(*regions)))) {
log_error("Could not allocate memory for region IDs.");
goto out;
goto_out;
}
/*
* Second pass (first for non-update case): create regions for
* all extents not retained from the prior mapping, and insert
* retained regions into the table of region_id values.
*
* If a regroup is not scheduled, set group bits for newly
* created regions in the group leader bitmap.
*/
for (i = 0; i < *count; i++) {
if (update) {
if ((old_ext = _find_extent(nr_kept, old_extents,
extents[i].start,
extents[i].len))) {
regions[i] = old_ext->id;
continue;
}
}
if (!_stats_create_region(dms, regions + i, extents[i].start,
extents[i].len, -1, precise, hist_arg,
dms->program_id, "")) {
@@ -4491,13 +4693,39 @@ static uint64_t *_stats_create_file_regions(struct dm_stats *dms, int fd,
extents[i].start);
goto out_remove;
}
log_very_verbose("Created new region mapping " FMTu64 "+" FMTu64
" with region ID " FMTu64, extents[i].start,
extents[i].len, regions[i]);
if (!*regroup && update) {
/* expand group bitmap */
if (regions[i] > (group->regions[0] - 1)) {
num_bits = regions[i] + *count;
if (!_stats_resize_group(group, num_bits)) {
log_error("Failed to resize group "
"bitmap.");
goto out_remove;
}
}
dm_bit_set(group->regions, regions[i]);
}
}
regions[*count] = DM_STATS_REGION_NOT_PRESENT;
/* Update group leader aux_data for new group members. */
if (!*regroup && update)
if (!_stats_set_aux(dms, group_id,
dms->regions[group_id].aux_data))
log_error("Failed to update group aux_data.");
if (bounds)
dm_free(hist_arg);
dm_pool_free(extent_mem, extents);
dm_pool_destroy(extent_mem);
dm_free(hist_arg);
return regions;
out_remove:
@@ -4511,13 +4739,15 @@ out_remove:
dm_stats_list(dms, NULL);
fail_region = i;
for (i = 0; i < fail_region; i++)
if (!_stats_delete_region(dms, regions[i]))
log_error("Could not delete region " FMTu64 ".", i);
_stats_cleanup_region_ids(dms, regions, fail_region);
*count = 0;
out:
/*
* The table of file extents in 'extents' is always built, so free
* it explicitly: this will also free any 'old_extents' table that
* was later allocated from the 'extent_mem' pool by this function.
*/
dm_pool_free(extent_mem, extents);
dm_pool_destroy(extent_mem);
dm_free(hist_arg);
@@ -4531,15 +4761,16 @@ uint64_t *dm_stats_create_regions_from_fd(struct dm_stats *dms, int fd,
const char *alias)
{
uint64_t *regions, count = 0;
int regroup = 1;
if (alias && !group) {
log_error("Cannot set alias without grouping regions.");
return NULL;
}
regions = _stats_create_file_regions(dms, fd, bounds, precise, &count);
if (!regions)
return_0;
if (!(regions = _stats_map_file_regions(dms, fd, bounds, precise,
-1, &count, &regroup)))
return NULL;
if (!group)
return regions;
@@ -4553,11 +4784,97 @@ uint64_t *dm_stats_create_regions_from_fd(struct dm_stats *dms, int fd,
return regions;
out:
_stats_cleanup_region_ids(dms, regions, count);
dm_free(regions);
return NULL;
}
uint64_t *dm_stats_update_regions_from_fd(struct dm_stats *dms, int fd,
uint64_t group_id)
{
struct dm_histogram *bounds = NULL;
int nr_bins, precise, regroup;
uint64_t *regions, count = 0;
const char *alias = NULL;
if (!dms->regions || !dm_stats_group_present(dms, group_id)) {
if (!dm_stats_list(dms, dms->program_id)) {
log_error("Could not obtain region list while "
"updating group " FMTu64 ".", group_id);
return NULL;
}
}
if (!dm_stats_group_present(dms, group_id)) {
log_error("Group ID " FMTu64 " does not exist.", group_id);
return NULL;
}
/*
* If the extent corresponding to the group leader's region has been
* deallocated, _stats_map_file_regions() will remove the region and
* the group. In this case, regroup will be set by the call and the
* group will be re-created using saved values.
*/
regroup = 0;
/*
* A copy of the alias is needed to re-create the group when regroup=1.
*/
if (dms->groups[group_id].alias) {
alias = dm_strdup(dms->groups[group_id].alias);
if (!alias) {
log_error("Failed to allocate group alias string.");
return NULL;
}
}
if (dms->regions[group_id].bounds) {
/*
* A copy of the histogram bounds must be passed to
* _stats_map_file_regions() to be used when creating new
* regions: it is not safe to use the copy in the current group
* leader since it may be destroyed during the first group
* update pass.
*/
nr_bins = dms->regions[group_id].bounds->nr_bins;
bounds = _alloc_dm_histogram(nr_bins);
if (!bounds) {
log_error("Could not allocate memory for group "
"histogram bounds.");
return NULL;
}
_stats_copy_histogram_bounds(bounds,
dms->regions[group_id].bounds);
}
precise = (dms->regions[group_id].timescale == 1);
regions = _stats_map_file_regions(dms, fd, bounds, precise,
group_id, &count, &regroup);
if (!regions)
goto bad;
if (!dm_stats_list(dms, NULL))
goto bad;
if (regroup)
if (!_stats_group_file_regions(dms, regions, count, alias))
goto bad;
dm_free(bounds);
dm_free((char *) alias);
return regions;
bad:
_stats_cleanup_region_ids(dms, regions, count);
dm_free(bounds);
dm_free((char *) alias);
return NULL;
}
#else /* HAVE_LINUX_FIEMAP */
uint64_t *dm_stats_create_regions_from_fd(struct dm_stats *dms, int fd,
int group, int precise,
struct dm_histogram *bounds,
@@ -4566,6 +4883,13 @@ uint64_t *dm_stats_create_regions_from_fd(struct dm_stats *dms, int fd,
log_error("File mapping requires FIEMAP ioctl support.");
return 0;
}
uint64_t *dm_stats_update_regions_from_fd(struct dm_stats *dms, int fd,
uint64_t group_id)
{
log_error("File mapping requires FIEMAP ioctl support.");
return 0;
}
#endif /* HAVE_LINUX_FIEMAP */
/*

View File

@@ -468,10 +468,12 @@ const char *dm_size_to_string(struct dm_pool *mem, uint64_t size,
unsigned base = BASE_UNKNOWN;
unsigned s;
int precision;
double d;
uint64_t byte = UINT64_C(0);
uint64_t units = UINT64_C(1024);
char *size_buf = NULL;
char new_unit_type = '\0', unit_type_buf[2];
const char *prefix = "";
const char * const size_str[][3] = {
/* BASE_UNKNOWN */
{" ", " ", " "}, /* [0] */
@@ -570,7 +572,7 @@ const char *dm_size_to_string(struct dm_pool *mem, uint64_t size,
byte = unit_factor;
} else {
/* Human-readable style */
if (unit_type == 'H') {
if (unit_type == 'H' || unit_type == 'R') {
units = UINT64_C(1000);
base = BASE_1000;
} else {
@@ -586,6 +588,16 @@ const char *dm_size_to_string(struct dm_pool *mem, uint64_t size,
for (s = 0; s < NUM_UNIT_PREFIXES && size < byte; s++)
byte /= units;
if ((s < NUM_UNIT_PREFIXES) &&
((unit_type == 'R') || (unit_type == 'r'))) {
/* When the rounding would cause difference, add '<' prefix
* i.e. 2043M is more then 1.9949G prints <2.00G
* This version is for 2 digits fixed precision */
d = 100. * (double) size / byte;
if (!_close_enough(floorl(d), nearbyintl(d)))
prefix = "<";
}
include_suffix = 1;
}
@@ -599,7 +611,7 @@ const char *dm_size_to_string(struct dm_pool *mem, uint64_t size,
precision = 2;
}
snprintf(size_buf, SIZE_BUF - 1, "%.*f%s", precision,
snprintf(size_buf, SIZE_BUF - 1, "%s%.*f%s", prefix, precision,
(double) size / byte, include_suffix ? size_str[base + s][suffix_type] : "");
return size_buf;
@@ -639,6 +651,8 @@ uint64_t dm_units_to_factor(const char *units, char *unit_type,
switch (*units) {
case 'h':
case 'H':
case 'r':
case 'R':
multiplier = v = UINT64_C(1);
*unit_type = *units;
break;

View File

@@ -140,13 +140,6 @@ Makefile: Makefile.in
*) echo "Creating $@" ; $(SED) -e "s+#VERSION#+$(LVM_VERSION)+;s+#DEFAULT_SYS_DIR#+$(DEFAULT_SYS_DIR)+;s+#DEFAULT_ARCHIVE_DIR#+$(DEFAULT_ARCHIVE_DIR)+;s+#DEFAULT_BACKUP_DIR#+$(DEFAULT_BACKUP_DIR)+;s+#DEFAULT_PROFILE_DIR#+$(DEFAULT_PROFILE_DIR)+;s+#DEFAULT_CACHE_DIR#+$(DEFAULT_CACHE_DIR)+;s+#DEFAULT_LOCK_DIR#+$(DEFAULT_LOCK_DIR)+;s+#CLVMD_PATH#+@CLVMD_PATH@+;s+#LVM_PATH#+@LVM_PATH@+;s+#DEFAULT_RUN_DIR#+@DEFAULT_RUN_DIR@+;s+#DEFAULT_PID_DIR#+@DEFAULT_PID_DIR@+;s+#SYSTEMD_GENERATOR_DIR#+$(SYSTEMD_GENERATOR_DIR)+;s+#DEFAULT_MANGLING#+$(DEFAULT_MANGLING)+;" $< > $@ ;; \
esac
ccmd: ../tools/create-commands.c
$(CC) ../tools/create-commands.c -o ccmd
generate: ccmd
./ccmd --output man -s 0 -p 1 -c lvcreate ../tools/command-lines.in > lvcreate.8.a
cat lvcreate.8.a lvcreate.8.b > lvcreate.8.in
install_man5: $(MAN5)
$(INSTALL) -d $(MAN5DIR)
$(INSTALL_DATA) $(MAN5) $(MAN5DIR)/

View File

@@ -212,6 +212,17 @@ dmstats \(em device-mapper statistics management
. ad b
..
.CMD_UNGROUP
.HP
.B dmstats
.de CMD_UPDATE_FILEMAP
. ad l
. BR update_filemap
. RI file_path
. RB [ \-\-groupid
. IR id ]
. ad b
..
.CMD_UPDATE_FILEMAP
.
.PD
.ad b
@@ -668,6 +679,21 @@ Remove an existing group and return all the group's regions to their
original state.
The group to be removed is specified using \fB\-\-groupid\fP.
.HP
.CMD_UPDATE_FILEMAP
.br
Update a group of \fBdmstats\fP regions specified by \fBgroup_id\fP,
that were previously created with \fB\-\-filemap\fP. This will add
and remove regions to reflect changes in the allocated extents of
the file on-disk, since the time that it was crated or last updated.
Use of this command is not normally needed since the \fBdmfilemapd\fP
daemon will automatically monitor filemap groups and perform these
updates when required.
If a filemapped group was created with \fB\-\-nominitor\fP, or the
daemon has been killed, the \fBupdate_filemap\fP can be used to
manually force an update.
.
.SH REGIONS, AREAS, AND GROUPS
.

View File

@@ -45,9 +45,6 @@ A file containing a simple script with one command per line
can also be given on the command line. The script can also be
executed directly if the first line is #! followed by the absolute
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
.
@@ -241,6 +238,261 @@ The following commands are not implemented in LVM2 but might be
in the future:
.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
.
The valid characters for VG and LV names are:
@@ -416,6 +668,11 @@ File descriptor to use for report output from LVM commands.
Name of default command profile to use for LVM commands. This profile
is overriden by direct use of \fB\-\-commandprofile\fP command line option.
.TP
.B LVM_RUN_BY_DMEVENTD
This variable is normally set by dmeventd plugin to inform lvm2 command
it is running from dmeventd plugin so lvm2 takes some extra action
to avoid comunication and deadlocks with dmeventd.
.TP
.B LVM_SYSTEM_DIR
Directory containing \fBlvm.conf\fP(5) and other LVM system files.
Defaults to "\fI#DEFAULT_SYS_DIR#\fP".

View File

@@ -171,7 +171,8 @@ device_umount_one() {
}
device_umount() {
test "$devtype" != "lvm" && test "${kname:0:3}" != "dm-" && return 0
test "$devtype" != "lvm" && test "${kname:0:3}" != "dm-" \
&& test "${kname:0:2}" != "md" && return 0
# FINDMNT is defined only if umount --all-targets is not available.
# In that case, read the list of multiple mount points of one device

View File

@@ -975,6 +975,31 @@ enable_dev() {
done
}
# Once there is $name.devtable
# this is a quick way to restore to this table entry
restore_from_devtable() {
local dev
local silent
if test "$1" = "--silent"; then
silent=1
shift
fi
rm -f debug.log strace.log
init_udev_transaction
for dev in "$@"; do
local name=$(echo "$dev" | sed -e 's,.*/,,')
dmsetup load "$name" "$name.devtable"
dmsetup resume "$name"
done
finish_udev_transaction
test -n "$silent" || for dev in "$@"; do
notify_lvmetad "$dev"
done
}
#
# Convert device to device with errors
# Takes the list of pairs of error segment from:len

View File

@@ -18,10 +18,20 @@ aux have_raid 1 3 2 || skip
aux prepare_vg 8
_sync() {
aux enable_dev $(< DEVICES)
aux wait_for_sync $vg $lv1
test -z "$1" || check raid_leg_status $vg $lv1 $1
# restore to delay_dev tables for all devices
aux restore_from_devtable $(< DEVICES)
}
# Delay legs so that rebuilding status characters can be read
for d in $(< DEVICES)
do
aux delay_dev "$d" 0 20 $(get first_extent_sector "$d")
aux delay_dev "$d" 0 50 $(get first_extent_sector "$d")
done
# rhbz 1064592
@@ -30,115 +40,101 @@ done
# Create an 8-way striped raid10 with 4 mirror
# groups and rebuild selected PVs.
lvcreate --type raid10 -m 1 -i 4 -l 2 -n $lv1 $vg
aux wait_for_sync $vg $lv1
_sync
# Rebuild 1st and 2nd device would rebuild a
# whole mirror group and needs to be rejected.
not lvchange --yes --rebuild "$dev1" --rebuild "$dev2" $vg/$lv1
not check raid_leg_status $vg $lv1 "aAaAAAAA"
aux wait_for_sync $vg $lv1
check raid_leg_status $vg $lv1 "AAAAAAAA"
_sync "AAAAAAAA"
# Rebuild 1st and 3rd device from different mirror groups is fine.
lvchange --yes --rebuild "$dev1" --rebuild "$dev3" $vg/$lv1
aux have_raid 1 9 && check raid_leg_status $vg $lv1 "aAaAAAAA"
aux wait_for_sync $vg $lv1
check raid_leg_status $vg $lv1 "AAAAAAAA"
_sync "AAAAAAAA"
# Rebuild devices 1, 3, 6 from different mirror groups is fine.
lvchange --yes --rebuild "$dev1" --rebuild "$dev3" --rebuild "$dev6" $vg/$lv1
aux have_raid 1 9 && check raid_leg_status $vg $lv1 "aAaAAaAA"
aux wait_for_sync $vg $lv1
check raid_leg_status $vg $lv1 "AAAAAAAA"
_sync "AAAAAAAA"
# Rebuild devices 1, 3, 5 and 6 with 5+6 being
# being a whole mirror group needs to be rejected.
not lvchange --yes --rebuild "$dev1" --rebuild "$dev3" --rebuild "$dev6" --rebuild "$dev5" $vg/$lv1
not check raid_leg_status $vg $lv1 "aAaAaaAA"
aux wait_for_sync $vg $lv1
check raid_leg_status $vg $lv1 "AAAAAAAA"
_sync "AAAAAAAA"
# Rebuild devices 1, 3, 5 and 7 from different mirror groups is fine.
lvchange --yes --rebuild "$dev1" --rebuild "$dev3" --rebuild "$dev5" --rebuild "$dev7" $vg/$lv1
aux have_raid 1 9 && check raid_leg_status $vg $lv1 "aAaAaAaA"
aux wait_for_sync $vg $lv1
_sync
# Rebuild devices 2, 4, 6 and 8 from different mirror groups is fine.
lvchange --yes --rebuild "$dev2" --rebuild "$dev4" --rebuild "$dev6" --rebuild "$dev8" $vg/$lv1
aux have_raid 1 9 && check raid_leg_status $vg $lv1 "AaAaAaAa"
aux wait_for_sync $vg $lv1
check raid_leg_status $vg $lv1 "AAAAAAAA"
_sync "AAAAAAAA"
##############################################
# Create an 8-legged raid1 and rebuild selected PVs
lvremove --yes $vg/$lv1
lvcreate --yes --type raid1 -m 7 -l 2 -n $lv1 $vg
aux wait_for_sync $vg $lv1
check raid_leg_status $vg $lv1 "AAAAAAAA"
_sync "AAAAAAAA"
# Rebuilding all raid1 legs needs to be rejected.
not lvchange --yes --rebuild "$dev1" --rebuild "$dev2" --rebuild "$dev3" --rebuild "$dev4" \
--rebuild "$dev5" --rebuild "$dev6" --rebuild "$dev7" --rebuild "$dev8" $vg/$lv1
not check raid_leg_status $vg $lv1 "aaaaaaaa"
aux wait_for_sync $vg $lv1
check raid_leg_status $vg $lv1 "AAAAAAAA"
_sync "AAAAAAAA"
# Rebuilding all but the raid1 master leg is fine.
lvchange --yes --rebuild "$dev2" --rebuild "$dev3" --rebuild "$dev4" \
--rebuild "$dev5" --rebuild "$dev6" --rebuild "$dev7" --rebuild "$dev8" $vg/$lv1
aux have_raid 1 9 && check raid_leg_status $vg $lv1 "Aaaaaaaa"
aux wait_for_sync $vg $lv1
check raid_leg_status $vg $lv1 "AAAAAAAA"
_sync "AAAAAAAA"
# Rebuilding the raid1 master leg is fine.
lvchange --yes --rebuild "$dev1" $vg/$lv1
aux have_raid 1 9 && check raid_leg_status $vg $lv1 "aAAAAAAA"
aux wait_for_sync $vg $lv1
check raid_leg_status $vg $lv1 "AAAAAAAA"
_sync "AAAAAAAA"
# Rebuild legs on devices 2, 4, 6 and 8 is fine.
lvchange --yes --rebuild "$dev2" --rebuild "$dev4" --rebuild "$dev6" --rebuild "$dev8" $vg/$lv1
aux have_raid 1 9 && check raid_leg_status $vg $lv1 "AaAaAaAa"
aux wait_for_sync $vg $lv1
check raid_leg_status $vg $lv1 "AAAAAAAA"
_sync "AAAAAAAA"
##############################################
# Create an 6-legged raid6 and rebuild selected PVs
lvremove --yes $vg/$lv1
lvcreate --yes --type raid6 -i 4 -l 2 -n $lv1 $vg
aux wait_for_sync $vg $lv1
check raid_leg_status $vg $lv1 "AAAAAA"
_sync "AAAAAA"
# Rebuilding all raid6 stripes needs to be rejected.
not lvchange --yes --rebuild "$dev1" --rebuild "$dev2" --rebuild "$dev3" \
--rebuild "$dev4" --rebuild "$dev5" --rebuild "$dev6" $vg/$lv1
not check raid_leg_status $vg $lv1 "aaaaaa"
aux wait_for_sync $vg $lv1
check raid_leg_status $vg $lv1 "AAAAAA"
_sync "AAAAAA"
# Rebuilding more than 2 raid6 stripes needs to be rejected.
not lvchange --yes --rebuild "$dev2" --rebuild "$dev4" --rebuild "$dev6" $vg/$lv1
not check raid_leg_status $vg $lv1 "AaAaAa"
aux wait_for_sync $vg $lv1
check raid_leg_status $vg $lv1 "AAAAAA"
_sync "AAAAAA"
# Rebuilding any 1 raid6 stripe is fine.
lvchange --yes --rebuild "$dev2" $vg/$lv1
aux have_raid 1 9 && check raid_leg_status $vg $lv1 "AaAAAA"
aux wait_for_sync $vg $lv1
_sync
lvchange --yes --rebuild "$dev5" $vg/$lv1
aux have_raid 1 9 && check raid_leg_status $vg $lv1 "AAAAaA"
aux wait_for_sync $vg $lv1
check raid_leg_status $vg $lv1 "AAAAAA"
_sync "AAAAAA"
# Rebuilding any 2 raid6 stripes is fine.
lvchange --yes --rebuild "$dev2" --rebuild "$dev4" $vg/$lv1
aux have_raid 1 9 && check raid_leg_status $vg $lv1 "AaAaAA"
aux wait_for_sync $vg $lv1
check raid_leg_status $vg $lv1 "AAAAAA"
_sync "AAAAAA"
lvchange --yes --rebuild "$dev1" --rebuild "$dev5" $vg/$lv1
aux have_raid 1 9 && check raid_leg_status $vg $lv1 "aAAAaA"
aux wait_for_sync $vg $lv1
check raid_leg_status $vg $lv1 "AAAAAA"
_sync "AAAAAA"
vgremove -ff $vg

View File

@@ -33,7 +33,7 @@ lvcreate -L3 -n cow $vg
not lvconvert -s cow $vg/$lv1
# Use cached LV with 'striped' cow volume
lvconvert -y -s $vg/$lv1 $vg/cow
lvconvert -y -s $vg/$lv1 cow
check lv_field $vg/cow segtype linear
check lv_field $vg/$lv1 segtype cache

View File

@@ -60,7 +60,7 @@ check lv_field $vg/$lv2 cache_settings "random_threshold=56,sequential_threshold
# Check swap of cache pool metadata
lvconvert --yes --type cache-pool --poolmetadata $lv4 $vg/$lv3
UUID=$(get lv_field $vg/$lv5 uuid)
lvconvert --yes --swapmetadata --poolmetadata $lv5 $vg/$lv3
lvconvert --yes --cachepool $vg/$lv3 --poolmetadata $lv5
check lv_field $vg/${lv3}_cmeta uuid "$UUID"
@@ -108,30 +108,30 @@ lvcreate -an -Zn -L 8 -n $lv4 $vg
invalid lvconvert --type cache --poolmetadata $vg/$lv2 $vg/$lv1
# Cannot mix with thins
not lvconvert --type cache --poolmetadata $vg/$lv2 --thinpool $vg/$lv1
not lvconvert --type cache --thin --poolmetadata $vg/$lv2 $vg/$lv1
invalid lvconvert --type cache --poolmetadata $vg/$lv2 --thinpool $vg/$lv1
invalid lvconvert --type cache --thin --poolmetadata $vg/$lv2 $vg/$lv1
# Undefined cached volume
not lvconvert --type cache --cachepool $vg/$lv1
not lvconvert --cache --cachepool $vg/$lv1
invalid lvconvert --type cache --cachepool $vg/$lv1
invalid lvconvert --cache --cachepool $vg/$lv1
# Single vg is required
not lvconvert --type cache --cachepool $vg/$lv1 --poolmetadata $vg1/$lv2 $vg/$lv3
not lvconvert --type cache --cachepool $vg/$lv1 --poolmetadata $lv2 $vg1/$lv3
not lvconvert --type cache --cachepool $vg1/$lv1 --poolmetadata $vg2/$lv2 $vg/$lv3
not lvconvert --type cache-pool --poolmetadata $vg2/$lv2 $vg1/$lv1
invalid lvconvert --type cache --cachepool $vg/$lv1 --poolmetadata $vg1/$lv2 $vg/$lv3
invalid lvconvert --type cache --cachepool $vg/$lv1 --poolmetadata $lv2 $vg1/$lv3
invalid lvconvert --type cache --cachepool $vg1/$lv1 --poolmetadata $vg2/$lv2 $vg/$lv3
invalid lvconvert --type cache-pool --poolmetadata $vg2/$lv2 $vg1/$lv1
not lvconvert --cachepool $vg1/$lv1 --poolmetadata $vg2/$lv2
invalid lvconvert --cachepool $vg1/$lv1 --poolmetadata $vg2/$lv2
# Invalid syntax, vg is unknown
not lvconvert --yes --cachepool $lv3 --poolmetadata $lv4
invalid lvconvert --yes --cachepool $lv3 --poolmetadata $lv4
# Invalid chunk size is <32KiB >1GiB
not lvconvert --type cache-pool --chunksize 16 --poolmetadata $lv2 $vg/$lv1
not lvconvert --type cache-pool --chunksize 2G --poolmetadata $lv2 $vg/$lv1
invalid lvconvert --type cache-pool --chunksize 16 --poolmetadata $lv2 $vg/$lv1
invalid lvconvert --type cache-pool --chunksize 2G --poolmetadata $lv2 $vg/$lv1
# Invalid chunk size is bigger then data size, needs to open VG
not lvconvert --yes --type cache-pool --chunksize 16M --poolmetadata $lv2 $vg/$lv1
fail lvconvert --yes --type cache-pool --chunksize 16M --poolmetadata $lv2 $vg/$lv1
lvremove -f $vg
@@ -142,7 +142,7 @@ lvcreate --type cache-pool -an -v -L 2 -n cpool $vg
lvcreate -H -L 4 -n corigin --cachepool $vg/cpool
# unsupported yet
not lvconvert --repair $vg/cpool 2>&1 | tee out
fail lvconvert --repair $vg/cpool 2>&1 | tee out
#grep "Cannot convert internal LV" out
lvremove -f $vg
@@ -154,13 +154,13 @@ lvcreate --type cache-pool -L10 $vg/$lv1
lvcreate --cache -L20 $vg/$lv1
lvcreate -L10 -n $lv2 $vg
not lvconvert --yes --type cache $vg/$lv2 --cachepool $vg/$lv1
not lvconvert --yes --type cache $vg/$lv1 --cachepool $vg/$lv2
not lvconvert --yes --type cache-pool $vg/$lv1
not lvconvert --yes --type mirror -m1 $vg/$lv1
fail lvconvert --yes --type cache $vg/$lv2 --cachepool $vg/$lv1
fail lvconvert --yes --type cache $vg/$lv1 --cachepool $vg/$lv2
fail lvconvert --yes --type cache-pool $vg/$lv1
fail lvconvert --yes --type mirror -m1 $vg/$lv1
not aux have_raid 1 0 0 || fail lvconvert --yes --type raid1 -m1 $vg/$lv1
not lvconvert --yes --type snapshot $vg/$lv1 $vg/$lv2
not lvconvert --yes --type snapshot $vg/$lv2 $vg/$lv1
fail lvconvert --yes --type snapshot $vg/$lv1 $vg/$lv2
fail lvconvert --yes --type snapshot $vg/$lv2 $vg/$lv1
not aux have_thin 1 0 0 || fail lvconvert --yes -T --thinpool $vg/$lv2 $vg/$lv1
lvremove -f $vg

View File

@@ -85,9 +85,12 @@ offset=$(( offset + 2 ))
# update in case mirror ever gets faster and allows parallel read
aux delay_dev "$dev2" 0 2000 ${offset}:1
lvcreate -aey -l5 -Zn -Wn --type mirror --regionsize 16K -m2 -n $lv1 $vg "$dev1" "$dev2" "$dev4" "$dev3:$DEVRANGE"
# FIXME: add a new explicit option to define the polling behavior
# done here with 'lvconvert vg/lv'. That option can specify
# that the command succeeds even if the LV doesn't need polling.
should not lvconvert -m-1 $vg/$lv1 "$dev1"
aux enable_dev "$dev2"
lvconvert --startpoll $vg/$lv1 || true # wait
should lvconvert $vg/$lv1 # wait
lvconvert -m2 $vg/$lv1 "$dev1" "$dev2" "$dev4" "$dev3:0" # If the above "should" failed...
aux wait_for_sync $vg $lv1
@@ -113,7 +116,7 @@ LVM_TEST_TAG="kill_me_$PREFIX" lvconvert -m+1 -b $vg/$lv1 "$dev4"
# Next convert should fail b/c we can't have 2 at once
should not lvconvert -m+1 $vg/$lv1 "$dev5"
aux enable_dev "$dev4"
lvconvert --startpoll $vg/$lv1 || true # wait
should lvconvert $vg/$lv1 # wait
lvconvert -m2 $vg/$lv1 # In case the above "should" actually failed
check mirror $vg $lv1 "$dev3"
@@ -156,7 +159,7 @@ lvcreate -aey -l2 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:$DEVRANGE
lvchange -an $vg/$lv1
lvconvert -m+1 $vg/$lv1 "$dev4"
lvchange -aey $vg/$lv1
lvconvert --startpoll $vg/$lv1 || true # wait
should lvconvert $vg/$lv1 # wait
check mirror $vg $lv1 "$dev3"
check mirror_no_temporaries $vg $lv1
lvremove -ff $vg
@@ -168,7 +171,7 @@ lvremove -ff $vg
lvcreate -aey -l2 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:$DEVRANGE"
LVM_TEST_TAG="kill_me_$PREFIX" lvconvert -m+1 -b $vg/$lv1 "$dev4"
lvconvert -m-1 $vg/$lv1 "$dev4"
lvconvert --startpoll $vg/$lv1 || true # wait
should lvconvert $vg/$lv1 # wait
check mirror $vg $lv1 "$dev3"
check mirror_no_temporaries $vg $lv1
@@ -179,7 +182,7 @@ lvremove -ff $vg
lvcreate -aey -l2 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:$DEVRANGE"
LVM_TEST_TAG="kill_me_$PREFIX" lvconvert -m+2 -b $vg/$lv1 "$dev4" "$dev5"
lvconvert -m-1 $vg/$lv1 "$dev4"
lvconvert --startpoll $vg/$lv1 || true # wait
should lvconvert $vg/$lv1 # wait
check mirror $vg $lv1 "$dev3"
check mirror_no_temporaries $vg $lv1
@@ -192,9 +195,9 @@ LVM_TEST_TAG="kill_me_$PREFIX" lvconvert -m+1 -b $vg/$lv1 "$dev4"
# FIXME: Extra wait here for mirror upconvert synchronization
# otherwise we may fail her on parallel upconvert and downconvert
# lvconvert-mirror-updown.sh tests this errornous case separately
lvconvert --startpoll $vg/$lv1 || true
should lvconvert $vg/$lv1
lvconvert -m-1 $vg/$lv1 "$dev2"
lvconvert --startpoll $vg/$lv1 || true
should lvconvert $vg/$lv1
check mirror $vg $lv1 "$dev3"
check mirror_no_temporaries $vg $lv1
@@ -207,9 +210,9 @@ LVM_TEST_TAG="kill_me_$PREFIX" lvconvert -m+1 -b $vg/$lv1 "$dev4"
# FIXME: Extra wait here for mirror upconvert synchronization
# otherwise we may fail her on parallel upconvert and downconvert
# lvconvert-mirror-updown.sh tests this errornous case separately
lvconvert --startpoll $vg/$lv1 || true
should lvconvert $vg/$lv1
lvconvert -m-1 $vg/$lv1 "$dev2"
lvconvert --startpoll $vg/$lv1 || true
should lvconvert $vg/$lv1
check mirror $vg $lv1 "$dev3"
check mirror_no_temporaries $vg $lv1

View File

@@ -79,12 +79,15 @@ vgextend $vg "$dev3"
lvremove -ff $vg/$lv1
# Delayed sync to allow for repair during rebuild
delay 50
delay 60
# RAID5 single replace during initial sync
lvcreate --type raid5 -i 2 -L $RAID_SIZE -n $lv1 $vg "$dev1" "$dev2" "$dev3"
aux disable_dev "$dev3"
not lvconvert -y --repair $vg/$lv1
# FIXME: there is quite big sleep on several 'status' read retries
# so over 3sec - it may actually finish full sync
# Use 'should' for this test result.
should not lvconvert -y --repair $vg/$lv1
aux wait_for_sync $vg $lv1
lvconvert -y --repair $vg/$lv1
vgreduce --removemissing $vg

View File

@@ -45,7 +45,7 @@ lvchange -an $vg/$lv2 $vg/$lv1 $vg/pool $vg/repair
# Manual repair steps:
# Test swapping - swap out thin-pool's metadata with our repair volume
lvconvert -y -f --swapmetadata --poolmetadata $vg/repair $vg/pool
lvconvert -y -f --poolmetadata $vg/repair --thinpool $vg/pool
lvchange -ay $vg/repair
@@ -74,7 +74,7 @@ not "$LVM_TEST_THIN_DUMP_CMD" "$DM_DEV_DIR/$vg/repair" | tee dump
lvchange -an $vg
# Swap repaired metadata back
lvconvert -y -f --swapmetadata --poolmetadata $vg/fixed $vg/pool
lvconvert -y -f --poolmetadata $vg/fixed --thinpool $vg/pool
# Check pool still preserves its original settings
check lv_field $vg/pool chunksize "128.00k"
@@ -87,7 +87,7 @@ vgchange -ay $vg
vgchange -an $vg
# Put back 'broken' metadata
lvconvert -y -f --swapmetadata --poolmetadata $vg/repair $vg/pool
lvconvert -y -f --poolmetadata $vg/repair --thinpool $vg/pool
# Check --repair usage
lvconvert -v --repair $vg/pool
@@ -98,7 +98,7 @@ lvchange -ay $vg/pool
vgchange -an $vg
# Restore damaged metadata
lvconvert -y -f --swapmetadata --poolmetadata $vg/pool_meta0 $vg/pool
lvconvert -y -f --poolmetadata $vg/pool_meta0 --thinpool $vg/pool
# Check lvremove -ff works even with damaged pool
lvremove -ff $vg

View File

@@ -50,11 +50,8 @@ not lvconvert --thin --thinpool $vg/tpool $vg/$lv1
# Switch to 'writethrough' - this should be supported
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
# Check $lv1 remains mounted (so it's not been unmounted by systemd)
not mount "$DM_DEV_DIR/$vg/$lv1" mnt
lvconvert --thin $vg/$lv1 --originname extorg --thinpool $vg/tpool

View File

@@ -30,8 +30,8 @@ aux wait_for_sync $vg $lv2
lvchange -an $vg/$lv1
# conversion fails for internal volumes
not lvconvert --thinpool $vg/${lv1}_rimage_0
not lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $vg/${lv2}_rimage_0
invalid lvconvert --thinpool $vg/${lv1}_rimage_0
invalid lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $vg/${lv2}_rimage_0
lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $vg/$lv2

View File

@@ -58,13 +58,13 @@ lvchange -an $vg/$lv1
# conversion fails for mirror segment type
fail lvconvert --thinpool $vg/$lv1
# cannot use same LV
not lvconvert --yes --thinpool $vg/$lv2 --poolmetadata $vg/$lv2
invalid lvconvert --yes --thinpool $vg/$lv2 --poolmetadata $vg/$lv2
prepare_lvs
# conversion fails for internal volumes
# can't use --readahead with --poolmetadata
not lvconvert --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 --readahead 512
invalid lvconvert --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 --readahead 512
lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
prepare_lvs
@@ -81,9 +81,9 @@ grep "Pool zeroing and large" err
UUID=$(get lv_field $vg/$lv2 uuid)
# Fail is pool is active
# TODO maybe detect inactive pool and deactivate
fail lvconvert --swapmetadata --yes --poolmetadata $lv2 $vg/$lv1
fail lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $lv2
lvchange -an $vg
lvconvert --swapmetadata --yes --poolmetadata $lv2 $vg/$lv1
lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $lv2
check lv_field $vg/${lv1}_tmeta uuid "$UUID"
lvremove -f $vg
@@ -96,20 +96,20 @@ lvcreate -L1M -n $lv3 $vg
# chunk size is bigger then size of thin pool data
fail lvconvert --yes -c 1G --thinpool $vg/$lv3
# stripes can't be used with poolmetadata
not lvconvert --stripes 2 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
invalid lvconvert --stripes 2 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
# too small metadata (<2M)
fail lvconvert --yes -c 64 --thinpool $vg/$lv1 --poolmetadata $vg/$lv3
# too small chunk size fails
not lvconvert -c 4 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
invalid lvconvert -c 4 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
# too big chunk size fails
not lvconvert -c 2G --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
invalid lvconvert -c 2G --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
# negative chunk size fails
not lvconvert -c -256 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
invalid lvconvert -c -256 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
# non multiple of 64KiB fails
not lvconvert -c 88 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
invalid lvconvert -c 88 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
# cannot use same LV for pool and convertion
not lvconvert --yes --thinpool $vg/$lv3 -T $vg/$lv3
invalid lvconvert --yes --thinpool $vg/$lv3 -T $vg/$lv3
# Warning about smaller then suggested
lvconvert --yes -c 256 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 2>&1 | tee err
@@ -129,7 +129,7 @@ if test "$TSIZE" = 64T; then
lvcreate -L24T -n $lv1 $vg
# Warning about bigger then needed (24T data and 16G -> 128K chunk)
lvconvert --yes -c 64 --thinpool $vg/$lv1 2>&1 | tee err
grep "too small" err
grep "WARNING: Chunk size is too small" err
lvremove -f $vg
fi

View File

@@ -56,7 +56,7 @@ fail lvcreate -l 1 --cachepool pool8 $vg
# no size specified
invalid lvcreate --cachepool pool $vg 2>&1 | tee err
# grep "specify either size or extents" err
grep "specify either size or extents" err
# Check nothing has been created yet
check vg_field $vg lv_count 0

View File

@@ -32,15 +32,15 @@ pvcreate "$DM_DEV_DIR/$vg/$lv"
vgcreate $vg1 "$DM_DEV_DIR/$vg/$lv"
lvcreate -l 100%FREE -n $lv1 $vg1
check lv_field $vg1/$lv1 size "1024.00t"
check lv_field $vg1/$lv1 size "1024.00t" --units t
lvresize -f -l 72%VG $vg1/$lv1
check lv_field $vg1/$lv1 size "737.28t"
check lv_field $vg1/$lv1 size "737.28t" --units t
lvremove -ff $vg1/$lv1
lvcreate -l 100%VG -n $lv1 $vg1
check lv_field $vg1/$lv1 size "1024.00t"
check lv_field $vg1/$lv1 size "1024.00t" --units t
lvresize -f -l 72%VG $vg1/$lv1
check lv_field $vg1/$lv1 size "737.28t"
check lv_field $vg1/$lv1 size "737.28t" --units t
lvremove -ff $vg1/$lv1
lvremove -ff $vg/$lv

View File

@@ -21,67 +21,68 @@ aux have_raid4 && segtypes="raid4 raid5"
aux prepare_vg 6
_sync() {
aux enable_dev "$dev1"
aux wait_for_sync $vg $lv1
test -z "$1" || check raid_leg_status $vg $lv1 $1
lvremove --yes $vg/$lv1
# restore to delay_dev tables for all devices
aux restore_from_devtable "$dev1"
}
# Delay 1st leg so that rebuilding status characters
# can be read before resync finished too quick.
aux delay_dev "$dev1" 0 50 $(get first_extent_sector "$dev1")
aux delay_dev "$dev1" 0 90 $(get first_extent_sector "$dev1")
# raid0/raid0_meta don't support resynchronization
for r in raid0 raid0_meta
do
lvcreate --yes --type $r -i 3 -l 1 -n $lv1 $vg
lvcreate --type $r -i 3 -l 1 -n $lv1 $vg
check raid_leg_status $vg $lv1 "AAA"
lvremove --yes $vg/$lv1
done
# raid1 supports resynchronization
lvcreate --yes --type raid1 -m 2 -l 2 -n $lv1 $vg
lvcreate --type raid1 -m 2 -l 4 -n $lv1 $vg
check raid_leg_status $vg $lv1 "aaa"
aux wait_for_sync $vg $lv1
check raid_leg_status $vg $lv1 "AAA"
lvremove --yes $vg/$lv1
_sync "AAA"
# raid1 supports --nosync
lvcreate --yes --type raid1 --nosync -m 2 -l 1 -n $lv1 $vg
lvcreate --type raid1 --nosync -m 2 -l 1 -n $lv1 $vg
check raid_leg_status $vg $lv1 "AAA"
lvremove --yes $vg/$lv1
for r in $segtypes
do
# raid4/5 support resynchronization
lvcreate --yes --type $r -i 3 -l 2 -n $lv1 $vg
lvcreate --type $r -i 3 -l 4 -n $lv1 $vg
check raid_leg_status $vg $lv1 "aaaa"
aux wait_for_sync $vg $lv1
check raid_leg_status $vg $lv1 "AAAA"
_sync "AAAA"
# raid4/5 support --nosync
lvcreate --yes --type $r --nosync -i 3 -l 1 -n $lv2 $vg
lvcreate --type $r --nosync -i 3 -l 1 -n $lv2 $vg
check raid_leg_status $vg $lv2 "AAAA"
lvremove --yes $vg
done
# raid6 supports resynchronization
lvcreate --yes --type raid6 -i 3 -l 2 -n $lv1 $vg
lvcreate --type raid6 -i 3 -l 4 -n $lv1 $vg
check raid_leg_status $vg $lv1 "aaaaa"
aux wait_for_sync $vg $lv1
check raid_leg_status $vg $lv1 "AAAAA"
lvremove --yes $vg/$lv1
_sync "AAAAA"
# raid6 rejects --nosync; it has to initialize P- and Q-Syndromes
not lvcreate --yes --type raid6 --nosync -i 3 -l 1 -n $lv1 $vg
not lvcreate --type raid6 --nosync -i 3 -l 1 -n $lv1 $vg
# raid10 supports resynchronization
lvcreate --yes --type raid10 -m 1 -i 3 -l 2 -n $lv1 $vg
lvcreate --type raid10 -m 1 -i 3 -l 4 -n $lv1 $vg
check raid_leg_status $vg $lv1 "aaaaaa"
aux wait_for_sync $vg $lv1
check raid_leg_status $vg $lv1 "AAAAAA"
aux wait_for_sync $vg $lv1
lvremove --yes $vg/$lv1
_sync "AAAAAA"
# raid10 supports --nosync
lvcreate --yes --type raid10 --nosync -m 1 -i 3 -l 1 -n $lv1 $vg
lvcreate --type raid10 --nosync -m 1 -i 3 -l 1 -n $lv1 $vg
check raid_leg_status $vg $lv1 "AAAAAA"
aux wait_for_sync $vg $lv1
lvremove --yes $vg/$lv1
vgremove -ff $vg

View File

@@ -38,7 +38,7 @@ lvchange -an $vg
lvcreate -L2M -n $lv1 $vg
"$LVM_TEST_THIN_RESTORE_CMD" -i data -o "$DM_DEV_DIR/mapper/$vg-$lv1"
lvconvert -y --swapmetadata --poolmetadata $vg/$lv1 $vg/pool
lvconvert -y --thinpool $vg/pool --poolmetadata $vg/$lv1
# Cannot resize if set to 0%
not lvextend --use-policies --config 'activation{thin_pool_autoextend_percent = 0}' $vg/pool 2>&1 | tee err

View File

@@ -78,7 +78,7 @@ fake_metadata_ 400 2 >data
"$LVM_TEST_THIN_RESTORE_CMD" -i data -o "$DM_DEV_DIR/mapper/$vg-$lv1"
# Swap volume with restored fake metadata
lvconvert -y --chunksize 64k --swapmetadata --poolmetadata $vg/$lv1 $vg/pool
lvconvert -y --chunksize 64k --thinpool $vg/pool --poolmetadata $vg/$lv1
# Not alllowed when thin-pool metadata free space is <75% for 2M meta
fail lvcreate -V20 $vg/pool
@@ -91,7 +91,7 @@ lvchange -an $vg/pool
fake_metadata_ 7400 2 >data
"$LVM_TEST_THIN_RESTORE_CMD" -i data -o "$DM_DEV_DIR/mapper/$vg-$lv2"
# Swap volume with restored fake metadata
lvconvert -y --chunksize 64k --swapmetadata --poolmetadata $vg/$lv2 $vg/pool
lvconvert -y --chunksize 64k --thinpool $vg/pool --poolmetadata $vg/$lv2
lvchange -ay $vg/pool
# Check generated metadata consume more then 88%
test "$(meta_percent_)" -gt "88"
@@ -138,7 +138,7 @@ lvchange -an $vg/thin $vg/thin2 $vg/pool
# Transaction_id is lower by 1 and there are no messages -> ERROR
fake_metadata_ 10 0 >data
"$LVM_TEST_THIN_RESTORE_CMD" -i data -o "$DM_DEV_DIR/mapper/$vg-$lv1"
lvconvert -y --swapmetadata --poolmetadata $vg/$lv1 $vg/pool
lvconvert -y --thinpool $vg/pool --poolmetadata $vg/$lv1
not vgchange -ay $vg 2>&1 | tee out
grep expected out
@@ -147,7 +147,7 @@ check inactive $vg pool_tmeta
# Transaction_id is higher by 1
fake_metadata_ 10 3 >data
"$LVM_TEST_THIN_RESTORE_CMD" -i data -o "$DM_DEV_DIR/mapper/$vg-$lv1"
lvconvert -y --swapmetadata --poolmetadata $vg/$lv1 $vg/pool
lvconvert -y --thinpool $vg/pool --poolmetadata $vg/$lv1
not vgchange -ay $vg 2>&1 | tee out
grep expected out
@@ -158,7 +158,7 @@ fake_metadata_ 400 2 >data
"$LVM_TEST_THIN_RESTORE_CMD" -i data -o "$DM_DEV_DIR/mapper/$vg-$lv1"
# Swap volume with restored fake metadata
lvconvert -y --chunksize 64k --swapmetadata --poolmetadata $vg/$lv1 $vg/pool
lvconvert -y --chunksize 64k --thinpool $vg/pool --poolmetadata $vg/$lv1
vgchange -ay $vg
@@ -173,7 +173,7 @@ fake_metadata_ 350 2 >data
lvchange -ay $vg/$lv1
"$LVM_TEST_THIN_RESTORE_CMD" -i data -o "$DM_DEV_DIR/mapper/$vg-$lv1"
lvconvert -y --chunksize 64k --swapmetadata --poolmetadata $vg/$lv1 $vg/pool
lvconvert -y --chunksize 64k --thinpool $vg/pool --poolmetadata $vg/$lv1
lvchange -ay $vg/pool $vg/$lv1
lvs -a $vg

View File

@@ -54,7 +54,7 @@ mkdir test_mnt
setup_merge_ $vg1 $lv1
mount "$(lvdev_ $vg1 $lv1)" test_mnt
lvconvert --mergesnapshot $vg1/$(snap_lv_name_ $lv1)
lvconvert --merge $vg1/$(snap_lv_name_ $lv1)
umount test_mnt
vgchange -an $vg1

View File

@@ -32,7 +32,7 @@ snap_and_merge() {
SLEEP_PID=$(aux hold_device_open $vg $lv1 20)
# initiate background merge
lvconvert -b --mergesnapshot $vg/$lv2
lvconvert -b --merge $vg/$lv2
lvs -a -o+lv_merging,lv_merge_failed $vg
get lv_field $vg/$lv1 lv_attr | grep "Owi-ao"

View File

@@ -51,15 +51,15 @@ mkdir test_mnt
# test full merge of a single LV
setup_merge_ $vg $lv1
# make sure lvconvert --mergesnapshot requires explicit LV listing
not lvconvert --mergesnapshot
lvconvert --mergesnapshot $vg/$(snap_lv_name_ $lv1)
# make sure lvconvert --merge requires explicit LV listing
not lvconvert --merge
lvconvert --merge $vg/$(snap_lv_name_ $lv1)
lvremove -f $vg/$lv1
# test that an actively merging snapshot may not be removed
setup_merge_ $vg $lv1
lvconvert -i+100 --mergesnapshot --background $vg/$(snap_lv_name_ $lv1)
lvconvert -i+100 --merge --background $vg/$(snap_lv_name_ $lv1)
not lvremove -f $vg/$(snap_lv_name_ $lv1)
lvremove -f $vg/$lv1
@@ -67,7 +67,7 @@ lvremove -f $vg/$lv1
# "onactivate merge" test
setup_merge_ $vg $lv1
mount "$(lvdev_ $vg $lv1)" test_mnt
lvconvert --mergesnapshot $vg/$(snap_lv_name_ $lv1)
lvconvert --merge $vg/$(snap_lv_name_ $lv1)
# -- refresh LV while FS is still mounted (merge must not start),
# verify 'snapshot-origin' target is still being used
lvchange --refresh $vg/$lv1
@@ -88,7 +88,7 @@ lvremove -f $vg/$lv1
# to make sure preload of origin's metadata is _not_ performed
setup_merge_ $vg $lv1
mount "$(lvdev_ $vg $lv1)" test_mnt
lvconvert --mergesnapshot $vg/$(snap_lv_name_ $lv1)
lvconvert --merge $vg/$(snap_lv_name_ $lv1)
# -- refresh LV while FS is still mounted (merge must not start),
# verify 'snapshot-origin' target is still being used
lvchange --refresh $vg/$lv1
@@ -99,7 +99,7 @@ lvremove -f $vg/$lv1
# test multiple snapshot merge; tests copy out that is driven by merge
setup_merge_ $vg $lv1 1
lvconvert --mergesnapshot $vg/$(snap_lv_name_ $lv1)
lvconvert --merge $vg/$(snap_lv_name_ $lv1)
lvremove -f $vg/$lv1
@@ -108,7 +108,7 @@ setup_merge_ $vg $lv1
setup_merge_ $vg $lv2
lvchange --addtag this_is_a_test $vg/$(snap_lv_name_ $lv1)
lvchange --addtag this_is_a_test $vg/$(snap_lv_name_ $lv2)
lvconvert --mergesnapshot @this_is_a_test
lvconvert --merge @this_is_a_test
lvs $vg | tee out
not grep $(snap_lv_name_ $lv1) out
not grep $(snap_lv_name_ $lv2) out

View File

@@ -16,6 +16,8 @@ SKIP_WITH_LVMPOLLD=1
export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
. lib/inittest
mntdir="${PREFIX}mnt with space"
mntusedir="${PREFIX}mntuse"
@@ -32,8 +34,6 @@ is_lv_opened_()
test $(get lv_field "$1" lv_device_open --binary) = "1"
}
. lib/inittest
#
# Main
#
@@ -42,6 +42,30 @@ export MKE2FS_CONFIG="$TESTDIR/lib/mke2fs.conf"
aux have_thin 1 0 0 || skip
aux lvmconf "dmeventd/thin_command = \"$PWD/testcmd.sh\""
# Simple implementation of umount when lvextend fails
cat <<- EOF >testcmd.sh
#!/bin/sh
echo "Data: \$DMEVENTD_THIN_POOL_DATA"
echo "Metadata: \$DMEVENTD_THIN_POOL_METADATA"
$TESTDIR/lib/lvextend --use-policies \$1 || {
umount "$mntdir" || true
umount "$mntusedir" || true
return 1
}
test \$($TESTDIR/lib/lvs -o selected -S "data_percent>95||metadata_percent>95" --noheadings \$1) -eq 0 || {
umount "$mntdir" || true
umount "$mntusedir" || true
return 1
}
EOF
chmod +x testcmd.sh
# Show prepared script
cat testcmd.sh
aux prepare_dmeventd
# Use autoextend percent 0 - so extension fails and triggers umount...

View File

@@ -71,7 +71,7 @@ aux prepare_thin_metadata 490 1 | tee data
"$LVM_TEST_THIN_RESTORE_CMD" -i data -o "$DM_DEV_DIR/mapper/$vg-$lv1"
# Swap volume with restored fake metadata
lvconvert -y --swapmetadata --poolmetadata $vg/$lv1 $vg/pool
lvconvert -y --thinpool $vg/pool --poolmetadata $vg/$lv1
lvchange -ay $vg

View File

@@ -44,7 +44,7 @@ touch mntsnap/test_snap
lvs -o+tags,thin_id $vg
lvconvert --mergethin $vg/snap
lvconvert --merge $vg/snap
umount mnt
@@ -102,12 +102,12 @@ lvcreate -s -n snap $vg/$lv1
lvcreate -s -L10 -n oldsnapof_${lv1} $vg/$lv1
not lvconvert --merge $vg/snap
$MKFS "$DM_DEV_DIR/$vg/oldsnapof_${lv1}"
lvconvert --mergesnapshot $vg/oldsnapof_${lv1}
lvconvert --merge $vg/oldsnapof_${lv1}
fsck -n "$DM_DEV_DIR/$vg/$lv1"
check lv_not_exists $vg oldsnapof_${lv1}
# Add old snapshot to thin snapshot
lvcreate -s -L10 -n oldsnapof_snap $vg/snap
lvconvert --mergethin $vg/snap
lvconvert --merge $vg/snap
lvremove -f $vg/oldsnapof_snap
vgremove -ff $vg

View File

@@ -34,7 +34,7 @@ mount "$DM_DEV_DIR/$vg/$lv1" mnt
lvcreate -s -n snap $vg/$lv1
check lv_field $vg/snap thin_id "3"
lvconvert --mergethin $vg/snap
lvconvert --merge $vg/snap
umount mnt

View File

@@ -63,6 +63,11 @@ check vg_field $vg max_pv 4294967295
# vgchange -l MaxLogicalVolumes
check vg_field $vg max_lv 0
invalid vgchange -l -128 $vg
vgchange -l 4294967295 $vg
invalid vgchange -l 4294967296 $vg
invalid vgchange -l 18446744073709551615 $vg
invalid vgchange -l 18446744073709551616 $vg
check vg_field $vg max_lv 4294967295
vgchange -l 128 $vg
check vg_field $vg max_lv 128

View File

@@ -23,6 +23,7 @@ lvcreate -l 1 -n lv1 $vg "$dev1"
invalid vgextend
# --metadatacopies => use --pvmetadatacopies
invalid vgextend --metadatacopies 3 $vg "$dev1" 2>&1 | tee out
grep -- "use --pvmetadatacopies" out
# VG name should exist
fail vgextend --restoremissing $vg-invalid "$dev1"

View File

@@ -1,4 +1,3 @@
#
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
@@ -77,7 +76,6 @@ SOURCES2 =\
TARGETS =\
.commands \
command-lines.h \
liblvm2cmd.a \
lvm
@@ -101,8 +99,7 @@ LIB_VERSION = $(LIB_VERSION_LVM)
CLEAN_TARGETS = liblvm2cmd.$(LIB_SUFFIX) $(TARGETS_DM) \
liblvm2cmd.$(LIB_SUFFIX).$(LIB_VERSION) lvm-static.o \
liblvm2cmd-static.a dmsetup.static lvm.static \
$(LDDEPS) .exported_symbols_generated \
ccmd command-lines.h command-lines-count.h
$(LDDEPS) .exported_symbols_generated
ifeq ("@CMDLIB@", "yes")
TARGETS += liblvm2cmd.$(LIB_SUFFIX).$(LIB_VERSION)
@@ -141,8 +138,6 @@ all: device-mapper
CFLAGS_lvm.o += $(EXTRA_EXEC_CFLAGS)
CFLAGS_lvmcmdline.o += $(VALGRIND_CFLAGS)
INCLUDES += -I$(top_builddir)/tools
lvm: $(OBJECTS) lvm.o $(top_builddir)/lib/liblvm-internal.a
$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) -o $@ $(OBJECTS) lvm.o \
$(LVMLIBS) $(READLINE_LIBS) $(LIBS) -rdynamic
@@ -176,36 +171,6 @@ liblvm2cmd.$(LIB_SUFFIX).$(LIB_VERSION): liblvm2cmd.$(LIB_SUFFIX)
$(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
ccmd: $(srcdir)/create-commands.c
$(CC) $(srcdir)/create-commands.c -o ccmd
.DELETE_ON_ERROR:
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)", "")
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
-include $(top_builddir)/libdm/libdevmapper.cflow

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,207 +0,0 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _LVM_COMMAND_H
#define _LVM_COMMAND_H
struct cmd_context;
/* old per-command-name function */
typedef int (*command_fn) (struct cmd_context *cmd, int argc, char **argv);
/* new per-command-line-id functions */
typedef int (*command_line_fn) (struct cmd_context *cmd, int argc, char **argv);
struct command_function {
int command_line_enum;
command_line_fn fn;
};
struct command_name {
const char *name;
const char *desc; /* general command description from commands.h */
unsigned int flags;
/* union of {required,optional}_opt_args for all commands with this name */
int valid_args[ARG_COUNT];
int num_args;
};
/*
* Command defintion
*
* A command is defined in terms of a command name,
* required options (+args), optional options (+args),
* required positional args, optional positional args.
*
* A positional arg always has non-zero pos_arg.def.types.
* The first positional arg has pos_arg.pos of 1.
*/
/* arg_def flags */
#define ARG_DEF_FLAG_NEW_VG 1 << 0
#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)
{
return (val_bits & (1 << val_enum)) ? 1 : 0;
}
static inline uint64_t val_enum_to_bit(int val_enum)
{
return (1ULL << val_enum);
}
static inline int lvp_bit_is_set(uint64_t lvp_bits, int lvp_enum)
{
return (lvp_bits & (1 << lvp_enum)) ? 1 : 0;
}
static inline uint64_t lvp_enum_to_bit(int lvp_enum)
{
return (1ULL << lvp_enum);
}
static inline int lvt_bit_is_set(uint64_t lvt_bits, int lvt_enum)
{
return (lvt_bits & (1 << lvt_enum)) ? 1 : 0;
}
static inline uint64_t lvt_enum_to_bit(int lvt_enum)
{
return (1ULL << lvt_enum);
}
/* Description a value that follows an option or exists in a position. */
struct arg_def {
uint64_t val_bits; /* bits of x_VAL, can be multiple for pos_arg */
uint64_t lvt_bits; /* lvt_enum_to_bit(x_LVT) for lv_VAL, can be multiple */
uint64_t num; /* a literal number for conststr_VAL */
const char *str; /* a literal string for constnum_VAL */
uint32_t flags; /* ARG_DEF_FLAG_ */
};
/* Description of an option and the value that follows it. */
struct opt_arg {
int opt; /* option, e.g. foo_ARG */
struct arg_def def; /* defines accepted values */
};
/* Description of a position and the value that exists there. */
struct pos_arg {
int pos; /* position, e.g. first is 1 */
struct arg_def def; /* defines accepted values */
};
/*
*
* Commands using a given command definition must follow a set
* of rules. If a given command+LV matches the conditions in
* opts/lvt_bits/lvp_bits, then the checks are applied.
* If one condition is not met, the checks are not applied.
* If no conditions are set, the checks are always applied.
*/
#define RULE_INVALID 1
#define RULE_REQUIRE 2
struct cmd_rule {
int *opts; /* if any option in this list is set, the check may apply */
uint64_t lvt_bits; /* if LV has one of these types (lvt_enum_to_bit), the check may apply */
uint64_t lvp_bits; /* if LV has all of these properties (lvp_enum_to_bit), the check may apply */
int *check_opts; /* used options must [not] be in this list */
uint64_t check_lvt_bits; /* LV must [not] have one of these type */
uint64_t check_lvp_bits; /* LV must [not] have all of these properties */
uint32_t rule; /* RULE_INVALID, RULE_REQUIRE: check values must [not] be true */
int opts_count; /* entries in opts[] */
int check_opts_count; /* entries in check_opts[] */
};
/*
* CMD_RO_ARGS needs to accomodate a list of options,
* of which one is required after which the rest are
* optional.
*/
#define CMD_RO_ARGS 64 /* required opt args */
#define CMD_OO_ARGS 150 /* optional opt args */
#define CMD_RP_ARGS 8 /* required 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 */
/*
* one or more from required_opt_args is required,
* then the rest are optional.
*/
#define CMD_FLAG_ONE_REQUIRED_OPT 1
#define CMD_FLAG_SECONDARY_SYNTAX 2
/* a register of the lvm commands */
struct command {
const char *name;
const char *desc; /* specific command description from command-lines.h */
const char *usage; /* excludes common options like --help, --debug */
const char *usage_common; /* includes commmon options like --help, --debug */
const char *command_line_id;
int command_line_enum; /* <command_line_id>_CMD */
struct command_name *cname;
command_fn fn; /* old style */
struct command_function *functions; /* new style */
unsigned int flags; /* copied from command_name.flags from commands.h */
unsigned int cmd_flags; /* CMD_FLAG_ */
/* definitions of opt/pos args */
/* required args following an --opt */
struct opt_arg required_opt_args[CMD_RO_ARGS];
/* optional args following an --opt */
struct opt_arg optional_opt_args[CMD_OO_ARGS];
/* required positional args */
struct pos_arg required_pos_args[CMD_RP_ARGS];
/* optional positional 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];
int ro_count;
int oo_count;
int rp_count;
int op_count;
int io_count;
/* used for processing current position */
int pos_count;
int rule_count;
};
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -4957,16 +4957,8 @@ static char *_get_abspath(const char *path)
return _path;
}
static int _stats_create_file(CMD_ARGS)
static int _stats_check_filemap_switches(void)
{
const char *alias, *program_id = DM_STATS_PROGRAM_ID;
const char *bounds_str = _string_args[BOUNDS_ARG];
uint64_t *regions, *region, count = 0;
struct dm_histogram *bounds = NULL;
char *path, *abspath = NULL;
struct dm_stats *dms = NULL;
int group, fd = -1, precise;
if (_switches[AREAS_ARG] || _switches[AREA_SIZE_ARG]) {
log_error("--filemap is incompatible with --areas and --area-size.");
return 0;
@@ -4997,6 +4989,27 @@ static int _stats_create_file(CMD_ARGS)
return 0;
}
return 1;
}
static int _stats_create_file(CMD_ARGS)
{
const char *alias, *program_id = DM_STATS_PROGRAM_ID;
const char *bounds_str = _string_args[BOUNDS_ARG];
uint64_t *regions, *region, count = 0;
struct dm_histogram *bounds = NULL;
char *path, *abspath = NULL;
struct dm_stats *dms = NULL;
int group, fd = -1, precise;
if (names) {
err("Device names are not compatibile with --filemap.");
return 0;
}
if (!_stats_check_filemap_switches())
return 0;
/* _stats_create_file does not use _process_all() */
if (!argc) {
log_error("--filemap requires a file path argument");
@@ -5598,6 +5611,105 @@ out:
return r;
}
static int _stats_update_file(CMD_ARGS)
{
uint64_t group_id, *region, *regions, count = 0;
const char *program_id = DM_STATS_PROGRAM_ID;
struct dm_stats *dms;
char *path, *abspath;
int fd = -1;
if (names) {
err("Device names are not compatibile with update_filemap.");
return 0;
}
if (!_stats_check_filemap_switches())
return 0;
/* _stats_update_file does not use _process_all() */
if (!argc) {
log_error("update_filemap requires a file path argument");
return 0;
}
if (!_switches[GROUP_ID_ARG]) {
err("--groupid is required to update a filemap group.");
return 0;
}
path = argv[0];
if (!(abspath = _get_abspath(path))) {
log_error("Could not canonicalize file name: %s", path);
return 0;
}
group_id = (uint64_t) _int_args[GROUP_ID_ARG];
if (_switches[PROGRAM_ID_ARG])
program_id = _string_args[PROGRAM_ID_ARG];
if (!strlen(program_id) && !_switches[FORCE_ARG])
program_id = DM_STATS_PROGRAM_ID;
if (!(dms = dm_stats_create(DM_STATS_PROGRAM_ID)))
goto_bad;
fd = open(abspath, O_RDONLY);
if (fd < 0) {
log_error("Could not open %s for reading", abspath);
goto bad;
}
if (!dm_stats_bind_from_fd(dms, fd))
goto_bad;
if (!strlen(program_id))
/* force creation of a region with no id */
dm_stats_set_program_id(dms, 1, NULL);
regions = dm_stats_update_regions_from_fd(dms, fd, group_id);
if (close(fd))
log_error("Error closing %s", abspath);
fd = -1;
if (!regions) {
log_error("Could not update regions from file %s", abspath);
goto bad;
}
for (region = regions; *region != DM_STATS_REGIONS_ALL; region++)
count++;
if (group_id != regions[0]) {
printf("Group ID changed from " FMTu64 " to " FMTu64,
group_id, regions[0]);
group_id = regions[0];
}
printf("%s: Updated group ID " FMTu64 " with "FMTu64" region(s).\n",
path, group_id, count);
dm_free(regions);
dm_free(abspath);
dm_stats_destroy(dms);
return 1;
bad:
dm_free(abspath);
if ((fd > -1) && close(fd))
log_error("Error closing %s", path);
if (dms)
dm_stats_destroy(dms);
return 0;
}
/*
* Command dispatch tables and usage.
*/
@@ -5678,6 +5790,7 @@ static struct command _stats_subcommands[] = {
{"print", PRINT_OPTS, 0, -1, 1, 0, _stats_print},
{"report", REPORT_OPTS "[<device...>]", 0, -1, 1, 0, _stats_report},
{"ungroup", "--groupid <id> " UNGROUP_OPTS, 1, -1, 1, 0, _stats_ungroup},
{"update_filemap", "--groupid <id> <file_path>", 1, 1, 0, 0, _stats_update_file},
{"version", "", 0, -1, 1, 0, _version},
{NULL, NULL, 0, 0, 0, 0, NULL}
};

View File

@@ -1,56 +0,0 @@
/*
* NULL in the last arg can be replaced with actual
* calls to the lv_is_prop() function when those
* become functions (are #define now), take uniform
* args (e.g. some take cmd others don't), and are
* exposed in tools.h
*
* Until then, the lv_is_prop() functions are
* called indirectly through _lv_is_prop().
*/
lvp(LVP_NONE, "", NULL) /* enum value 0 means none */
lvp(is_locked_LVP, "lv_is_locked", NULL)
lvp(is_partial_LVP, "lv_is_partial", NULL)
lvp(is_virtual_LVP, "lv_is_virtual", NULL)
lvp(is_merging_LVP, "lv_is_merging", NULL)
lvp(is_merging_origin_LVP, "lv_is_merging_origin", NULL)
lvp(is_converting_LVP, "lv_is_converting", NULL)
lvp(is_external_origin_LVP, "lv_is_external_origin", NULL)
lvp(is_virtual_origin_LVP, "lv_is_virtual_origin", NULL)
lvp(is_not_synced_LVP, "lv_is_not_synced", NULL)
lvp(is_pending_delete_LVP, "lv_is_pending_delete", NULL)
lvp(is_error_when_full_LVP, "lv_is_error_when_full", NULL)
lvp(is_pvmove_LVP, "lv_is_pvmove", NULL)
lvp(is_removed_LVP, "lv_is_removed", NULL)
lvp(is_vg_writable_LVP, "lv_is_vg_writable", NULL)
/* kinds of sub LV */
lvp(is_thinpool_data_LVP, "lv_is_thinpool_data", NULL)
lvp(is_thinpool_metadata_LVP, "lv_is_thinpool_metadata", NULL)
lvp(is_cachepool_data_LVP, "lv_is_cachepool_data", NULL)
lvp(is_cachepool_metadata_LVP, "lv_is_cachepool_metadata", NULL)
lvp(is_mirror_image_LVP, "lv_is_mirror_image", NULL)
lvp(is_mirror_log_LVP, "lv_is_mirror_log", NULL)
lvp(is_raid_image_LVP, "lv_is_raid_image", NULL)
lvp(is_raid_metadata_LVP, "lv_is_raid_metadata", NULL)
/*
* is_thick_origin should be used instead of is_origin
* is_thick_snapshot is generally used as LV_snapshot from lv_types.h
*/
lvp(is_origin_LVP, "lv_is_origin", NULL)
lvp(is_thick_origin_LVP, "lv_is_thick_origin", NULL)
lvp(is_thick_snapshot_LVP, "lv_is_thick_snapshot", NULL)
lvp(is_thin_origin_LVP, "lv_is_thin_origin", NULL)
lvp(is_thin_snapshot_LVP, "lv_is_thin_snapshot", NULL)
lvp(is_cache_origin_LVP, "lv_is_cache_origin", NULL)
lvp(is_merging_cow_LVP, "lv_is_merging_cow", NULL)
lvp(is_cow_covering_origin_LVP, "lv_is_cow_covering_origin", NULL)
lvp(is_visible_LVP, "lv_is_visible", NULL)
lvp(is_historical_LVP, "lv_is_historical", NULL)
lvp(is_raid_with_tracking_LVP, "lv_is_raid_with_tracking", NULL)
lvp(LVP_COUNT, "", NULL)

View File

@@ -1,34 +0,0 @@
/*
* LV types used in command definitions. The type strings are used
* as LV suffixes, e.g. LV_type or LV_type1_type2.
*
* The final NULL arg can be replaced with lv_is_type() functions
* if the current lv_is_type #defines become functions and are
* moved to tools.h
*
* Until then, the lv_is_type() functions are called indirectly
* through _lv_is_type().
*/
lvt(LVT_NONE, "", NULL)
lvt(linear_LVT, "linear", NULL)
lvt(striped_LVT, "striped", NULL)
lvt(snapshot_LVT, "snapshot", NULL) /* lv_is_cow, lv_is_thick_snapshot */
lvt(thin_LVT, "thin", NULL)
lvt(thinpool_LVT, "thinpool", NULL)
lvt(cache_LVT, "cache", NULL)
lvt(cachepool_LVT, "cachepool", NULL)
lvt(mirror_LVT, "mirror", NULL)
lvt(raid_LVT, "raid", NULL)
lvt(raid0_LVT, "raid0", NULL)
lvt(raid1_LVT, "raid1", NULL)
lvt(raid4_LVT, "raid4", NULL)
lvt(raid5_LVT, "raid5", NULL)
lvt(raid6_LVT, "raid6", NULL)
lvt(raid10_LVT, "raid10", NULL)
lvt(error_LVT, "error", NULL)
lvt(zero_LVT, "zero", NULL)
lvt(LVT_COUNT, "", NULL)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -58,5 +58,5 @@ int lvdisplay(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
return process_each_lv(cmd, argc, argv, NULL, NULL, 0, NULL, NULL, &_lvdisplay_single);
return process_each_lv(cmd, argc, argv, NULL, NULL, 0, NULL, &_lvdisplay_single);
}

View File

@@ -45,9 +45,9 @@ static char *_list_cmds(const char *text, int state)
len = strlen(text);
}
while (i < _cmdline->num_command_names)
if (!strncmp(text, _cmdline->command_names[i++].name, len))
return strdup(_cmdline->command_names[i - 1].name);
while (i < _cmdline->num_commands)
if (!strncmp(text, _cmdline->commands[i++].name, len))
return strdup(_cmdline->commands[i - 1].name);
return NULL;
}
@@ -57,7 +57,7 @@ static char *_list_args(const char *text, int state)
{
static int match_no = 0;
static size_t len = 0;
static struct command_name *cname;
static struct command *com;
/* Initialise if this is a new completion attempt */
if (!state) {
@@ -65,40 +65,40 @@ static char *_list_args(const char *text, int state)
int j;
match_no = 0;
cname = NULL;
com = NULL;
len = strlen(text);
/* Find start of first word in line buffer */
while (isspace(*s))
s++;
/* Look for word in list of command names */
for (j = 0; j < _cmdline->num_command_names; j++) {
/* Look for word in list of commands */
for (j = 0; j < _cmdline->num_commands; j++) {
const char *p;
char *q = s;
p = _cmdline->command_names[j].name;
p = _cmdline->commands[j].name;
while (*p == *q) {
p++;
q++;
}
if ((!*p) && *q == ' ') {
cname = _cmdline->command_names + j;
com = _cmdline->commands + j;
break;
}
}
}
if (!cname)
if (!com)
return NULL;
/* Short form arguments */
if (len < 3) {
while (match_no < cname->num_args) {
while (match_no < com->num_args) {
char s[3];
char c;
if (!(c = (_cmdline->arg_props +
cname->valid_args[match_no++])->short_arg))
com->valid_args[match_no++])->short_arg))
continue;
sprintf(s, "-%c", c);
@@ -108,13 +108,13 @@ static char *_list_args(const char *text, int state)
}
/* Long form arguments */
if (match_no < cname->num_args)
match_no = cname->num_args;
if (match_no < com->num_args)
match_no = com->num_args;
while (match_no - cname->num_args < cname->num_args) {
while (match_no - com->num_args < com->num_args) {
const char *l;
l = (_cmdline->arg_props +
cname->valid_args[match_no++ - cname->num_args])->long_arg;
com->valid_args[match_no++ - com->num_args])->long_arg;
if (*(l + 2) && !strncmp(text, l, len))
return strdup(l);
}
@@ -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();
char *orig_command_log_selection = NULL;
int is_lastlog_cmd = 0, argc, ret, i;
int is_lastlog_cmd = 0, argc, ret;
char *input = NULL, *args[MAX_ARGS], **argv;
rl_readline_name = "lvm";
@@ -262,9 +262,6 @@ int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline)
add_history(input);
for (i = 0; i < MAX_ARGS; i++)
args[i] = NULL;
argv = args;
if (lvm_split(input, &argc, argv, MAX_ARGS) == MAX_ARGS) {

View File

@@ -19,11 +19,10 @@
struct cmd_context;
struct cmdline_context {
struct arg_props *arg_props;
struct command *commands;
int num_commands;
struct command_name *command_names;
int num_command_names;
struct arg_props *arg_props;
struct command *commands;
int num_commands;
int commands_size;
};
int lvm2_main(int argc, char **argv);

View File

@@ -30,12 +30,12 @@ void *cmdlib_lvm2_init(unsigned static_compile)
{
struct cmd_context *cmd;
lvm_register_commands();
init_is_static(static_compile);
if (!(cmd = init_lvm(1, 1)))
return NULL;
lvm_register_commands();
return (void *) cmd;
}
@@ -83,7 +83,10 @@ int lvm2_run(void *handle, const char *cmdline)
memlock_inc_daemon(cmd);
} else if (!strcmp(cmdline, "_memlock_dec"))
memlock_dec_daemon(cmd);
else
else if (!strcmp(cmdline, "_dmeventd_thin_command")) {
if (setenv(cmdline, find_config_tree_str(cmd, dmeventd_thin_command_CFG, NULL), 1))
ret = ECMD_FAILED;
} else
ret = lvm_run_command(cmd, argc, argv);
out:
@@ -95,10 +98,9 @@ int lvm2_run(void *handle, const char *cmdline)
return ret;
}
void lvm2_disable_dmeventd_monitoring(void *handle) {
init_dmeventd_monitor(DMEVENTD_MONITOR_IGNORE);
init_ignore_suspended_devices(1);
init_disable_dmeventd_monitoring(1); /* Lock settings */
void lvm2_disable_dmeventd_monitoring(void *handle)
{
init_run_by_dmeventd((struct cmd_context *) handle);
}
void lvm2_log_level(void *handle, int level)

File diff suppressed because it is too large Load Diff

View File

@@ -27,5 +27,5 @@ int lvremove(struct cmd_context *cmd, int argc, char **argv)
cmd->include_historical_lvs = 1;
return process_each_lv(cmd, argc, argv, NULL, NULL, READ_FOR_UPDATE, NULL,
NULL, &lvremove_single);
&lvremove_single);
}

View File

@@ -119,5 +119,5 @@ int lvscan(struct cmd_context *cmd, int argc, char **argv)
*/
}
return process_each_lv(cmd, argc, argv, NULL, NULL, 0, NULL, NULL, &lvscan_single);
return process_each_lv(cmd, argc, argv, NULL, NULL, 0, NULL, &lvscan_single);
}

View File

@@ -136,11 +136,14 @@ static int _check_merging_origin(const struct logical_volume *lv,
case SEG_STATUS_SNAPSHOT:
break;
default:
/* When inactive, it's technically merging */
if (status->info_ok && !status->info.exists)
break;
return 1;
}
/* Origin is gone */
log_debug_activation("Merge is progress, reporting merged LV %s.",
log_debug_activation("Merge is in progress, reporting merged LV %s.",
display_lvname(lv->snapshot->lv));
*merged = 1;
@@ -542,14 +545,14 @@ static int _report_all_in_vg(struct cmd_context *cmd, struct processing_handle *
r = _vgs_single(cmd, vg->name, vg, handle);
break;
case LVS:
r = process_each_lv_in_vg(cmd, vg, NULL, NULL, 0, handle, NULL,
r = process_each_lv_in_vg(cmd, vg, NULL, NULL, 0, handle,
do_lv_info && !do_lv_seg_status ? &_lvs_with_info_single :
!do_lv_info && do_lv_seg_status ? &_lvs_with_status_single :
do_lv_info && do_lv_seg_status ? &_lvs_with_info_and_status_single :
&_lvs_single);
break;
case SEGS:
r = process_each_lv_in_vg(cmd, vg, NULL, NULL, 0, handle, NULL,
r = process_each_lv_in_vg(cmd, vg, NULL, NULL, 0, handle,
do_lv_info && !do_lv_seg_status ? &_lvsegs_with_info_single :
!do_lv_info && do_lv_seg_status ? &_lvsegs_with_status_single :
do_lv_info && do_lv_seg_status ? &_lvsegs_with_info_and_status_single :
@@ -1124,7 +1127,7 @@ static int _do_report(struct cmd_context *cmd, struct processing_handle *handle,
if (args->full_report_vg)
r = _report_all_in_vg(cmd, handle, args->full_report_vg, LVS, lv_info_needed, lv_segment_status_needed);
else
r = process_each_lv(cmd, args->argc, args->argv, NULL, NULL, 0, handle, NULL,
r = process_each_lv(cmd, args->argc, args->argv, NULL, NULL, 0, handle,
lv_info_needed && !lv_segment_status_needed ? &_lvs_with_info_single :
!lv_info_needed && lv_segment_status_needed ? &_lvs_with_status_single :
lv_info_needed && lv_segment_status_needed ? &_lvs_with_info_and_status_single :
@@ -1158,7 +1161,7 @@ static int _do_report(struct cmd_context *cmd, struct processing_handle *handle,
if (args->full_report_vg)
r = _report_all_in_vg(cmd, handle, args->full_report_vg, SEGS, lv_info_needed, lv_segment_status_needed);
else
r = process_each_lv(cmd, args->argc, args->argv, NULL, NULL, 0, handle, NULL,
r = process_each_lv(cmd, args->argc, args->argv, NULL, NULL, 0, handle,
lv_info_needed && !lv_segment_status_needed ? &_lvsegs_with_info_single :
!lv_info_needed && lv_segment_status_needed ? &_lvsegs_with_status_single :
lv_info_needed && lv_segment_status_needed ? &_lvsegs_with_info_and_status_single :

View File

@@ -800,7 +800,10 @@ int vgcreate_params_set_from_args(struct cmd_context *cmd,
return 0;
}
if (arg_is_set(cmd, vgmetadatacopies_ARG))
if (arg_is_set(cmd, metadatacopies_ARG))
vp_new->vgmetadatacopies = arg_int_value(cmd, metadatacopies_ARG,
DEFAULT_VGMETADATACOPIES);
else if (arg_is_set(cmd, vgmetadatacopies_ARG))
vp_new->vgmetadatacopies = arg_int_value(cmd, vgmetadatacopies_ARG,
DEFAULT_VGMETADATACOPIES);
else
@@ -2325,606 +2328,10 @@ static struct lv_segment _historical_lv_segment = {
.origin_list = DM_LIST_HEAD_INIT(_historical_lv_segment.origin_list),
};
int opt_in_list_is_set(struct cmd_context *cmd, int *opts, int count,
int *match_count, int *unmatch_count)
{
int match = 0;
int unmatch = 0;
int i;
for (i = 0; i < count; i++) {
if (arg_is_set(cmd, opts[i]))
match++;
else
unmatch++;
}
if (match_count)
*match_count = match;
if (unmatch_count)
*unmatch_count = unmatch;
return match ? 1 : 0;
}
void opt_array_to_str(struct cmd_context *cmd, int *opts, int count,
char *buf, int len)
{
int pos = 0;
int ret;
int i;
for (i = 0; i < count; i++) {
ret = snprintf(buf + pos, len - pos, "%s ", arg_long_option_name(opts[i]));
if (ret >= len - pos)
break;
pos += ret;
}
buf[len - 1] = '\0';
}
static void lvp_bits_to_str(uint64_t bits, char *buf, int len)
{
struct lv_props *prop;
int lvp_enum;
int pos = 0;
int ret;
for (lvp_enum = 0; lvp_enum < LVP_COUNT; lvp_enum++) {
if (!(prop = get_lv_prop(lvp_enum)))
continue;
if (lvp_bit_is_set(bits, lvp_enum)) {
ret = snprintf(buf + pos, len - pos, "%s ", prop->name);
if (ret >= len - pos)
break;
pos += ret;
}
}
buf[len - 1] = '\0';
}
static void lvt_bits_to_str(uint64_t bits, char *buf, int len)
{
struct lv_types *type;
int lvt_enum;
int pos = 0;
int ret;
for (lvt_enum = 0; lvt_enum < LVT_COUNT; lvt_enum++) {
if (!(type = get_lv_type(lvt_enum)))
continue;
if (lvt_bit_is_set(bits, lvt_enum)) {
ret = snprintf(buf + pos, len - pos, "%s ", type->name);
if (ret >= len - pos)
break;
pos += ret;
}
}
buf[len - 1] = '\0';
}
/*
* This is the lv_prop function pointer used for lv_is_foo() #defines.
* Alternatively, lv_is_foo() could all be turned into functions.
*/
static int _lv_is_prop(struct cmd_context *cmd, struct logical_volume *lv, int lvp_enum)
{
switch (lvp_enum) {
case is_locked_LVP:
return lv_is_locked(lv);
case is_partial_LVP:
return lv_is_partial(lv);
case is_virtual_LVP:
return lv_is_virtual(lv);
case is_merging_LVP:
return lv_is_merging(lv);
case is_merging_origin_LVP:
return lv_is_merging_origin(lv);
case is_converting_LVP:
return lv_is_converting(lv);
case is_external_origin_LVP:
return lv_is_external_origin(lv);
case is_virtual_origin_LVP:
return lv_is_virtual_origin(lv);
case is_not_synced_LVP:
return lv_is_not_synced(lv);
case is_pending_delete_LVP:
return lv_is_pending_delete(lv);
case is_error_when_full_LVP:
return lv_is_error_when_full(lv);
case is_pvmove_LVP:
return lv_is_pvmove(lv);
case is_removed_LVP:
return lv_is_removed(lv);
case is_vg_writable_LVP:
return (lv->vg->status & LVM_WRITE) ? 1 : 0;
case is_thinpool_data_LVP:
return lv_is_thin_pool_data(lv);
case is_thinpool_metadata_LVP:
return lv_is_thin_pool_metadata(lv);
case is_cachepool_data_LVP:
return lv_is_cache_pool_data(lv);
case is_cachepool_metadata_LVP:
return lv_is_cache_pool_metadata(lv);
case is_mirror_image_LVP:
return lv_is_mirror_image(lv);
case is_mirror_log_LVP:
return lv_is_mirror_log(lv);
case is_raid_image_LVP:
return lv_is_raid_image(lv);
case is_raid_metadata_LVP:
return lv_is_raid_metadata(lv);
case is_origin_LVP: /* use lv_is_thick_origin */
return lv_is_origin(lv);
case is_thick_origin_LVP:
return lv_is_thick_origin(lv);
case is_thick_snapshot_LVP:
return lv_is_thick_snapshot(lv);
case is_thin_origin_LVP:
return lv_is_thin_origin(lv, NULL);
case is_thin_snapshot_LVP:
return lv_is_thin_snapshot(lv);
case is_cache_origin_LVP:
return lv_is_cache_origin(lv);
case is_merging_cow_LVP:
return lv_is_merging_cow(lv);
case is_cow_covering_origin_LVP:
return lv_is_cow_covering_origin(lv);
case is_visible_LVP:
return lv_is_visible(lv);
case is_historical_LVP:
return lv_is_historical(lv);
case is_raid_with_tracking_LVP:
return lv_is_raid_with_tracking(lv);
default:
log_error(INTERNAL_ERROR "unknown lv property value lvp_enum %d", lvp_enum);
}
return 0;
}
/*
* Check if an LV matches a given LV type enum.
*/
static int _lv_is_type(struct cmd_context *cmd, struct logical_volume *lv, int lvt_enum)
{
struct lv_segment *seg = first_seg(lv);
switch (lvt_enum) {
case striped_LVT:
return seg_is_striped(seg) && !lv_is_cow(lv);
case linear_LVT:
return seg_is_linear(seg) && !lv_is_cow(lv);
case snapshot_LVT:
return lv_is_cow(lv);
case thin_LVT:
return lv_is_thin_volume(lv);
case thinpool_LVT:
return lv_is_thin_pool(lv);
case cache_LVT:
return lv_is_cache(lv);
case cachepool_LVT:
return lv_is_cache_pool(lv);
case mirror_LVT:
return lv_is_mirror(lv);
case raid_LVT:
return lv_is_raid(lv);
case raid0_LVT:
return seg_is_raid0(seg);
case raid1_LVT:
return seg_is_raid1(seg);
case raid4_LVT:
return seg_is_raid4(seg);
#if 0
case raid5_LVT:
return seg_is_raid5(seg);
case raid6_LVT:
return seg_is_raid6(seg);
#endif
case raid10_LVT:
return seg_is_raid10(seg);
case error_LVT:
return !strcmp(seg->segtype->name, SEG_TYPE_NAME_ERROR);
case zero_LVT:
return !strcmp(seg->segtype->name, SEG_TYPE_NAME_ZERO);
default:
log_error(INTERNAL_ERROR "unknown lv type value lvt_enum %d", lvt_enum);
}
return 0;
}
int get_lvt_enum(struct logical_volume *lv)
{
struct lv_segment *seg = first_seg(lv);
/*
* The order these are checked is important, because a snapshot LV has
* a linear seg type.
*/
if (lv_is_cow(lv))
return snapshot_LVT;
if (seg_is_linear(seg))
return linear_LVT;
if (seg_is_striped(seg))
return striped_LVT;
if (lv_is_thin_volume(lv))
return thin_LVT;
if (lv_is_thin_pool(lv))
return thinpool_LVT;
if (lv_is_cache(lv))
return cache_LVT;
if (lv_is_cache_pool(lv))
return cachepool_LVT;
if (lv_is_mirror(lv))
return mirror_LVT;
if (lv_is_raid(lv))
return raid_LVT;
if (seg_is_raid0(seg))
return raid0_LVT;
if (seg_is_raid1(seg))
return raid1_LVT;
if (seg_is_raid4(seg))
return raid4_LVT;
#if 0
if (seg_is_raid5(seg))
return raid5_LVT;
if (seg_is_raid6(seg))
return raid6_LVT;
#endif
if (seg_is_raid10(seg))
return raid10_LVT;
if (!strcmp(seg->segtype->name, SEG_TYPE_NAME_ERROR))
return error_LVT;
if (!strcmp(seg->segtype->name, SEG_TYPE_NAME_ZERO))
return zero_LVT;
return 0;
}
/*
* Call lv_is_<type> for each <type>_LVT bit set in lvt_bits.
* If lv matches one of the specified lv types, then return 1.
*/
static int _lv_types_match(struct cmd_context *cmd, struct logical_volume *lv, uint64_t lvt_bits,
uint64_t *match_bits, uint64_t *unmatch_bits)
{
struct lv_types *type;
int lvt_enum;
int found_a_match = 0;
int match;
if (match_bits)
*match_bits = 0;
if (unmatch_bits)
*unmatch_bits = 0;
for (lvt_enum = 1; lvt_enum < LVT_COUNT; lvt_enum++) {
if (!lvt_bit_is_set(lvt_bits, lvt_enum))
continue;
if (!(type = get_lv_type(lvt_enum)))
continue;
/*
* All types are currently handled by _lv_is_type()
* because lv_is_type() are #defines and not exposed
* in tools.h
*/
if (!type->fn)
match = _lv_is_type(cmd, lv, lvt_enum);
else
match = type->fn(cmd, lv);
if (match)
found_a_match = 1;
if (match_bits && match)
*match_bits |= lvt_enum_to_bit(lvt_enum);
if (unmatch_bits && !match)
*unmatch_bits |= lvt_enum_to_bit(lvt_enum);
}
return found_a_match;
}
/*
* Call lv_is_<prop> for each <prop>_LVP bit set in lvp_bits.
* If lv matches all of the specified lv properties, then return 1.
*/
static int _lv_props_match(struct cmd_context *cmd, struct logical_volume *lv, uint64_t lvp_bits,
uint64_t *match_bits, uint64_t *unmatch_bits)
{
struct lv_props *prop;
int lvp_enum;
int found_a_mismatch = 0;
int match;
if (match_bits)
*match_bits = 0;
if (unmatch_bits)
*unmatch_bits = 0;
for (lvp_enum = 1; lvp_enum < LVP_COUNT; lvp_enum++) {
if (!lvp_bit_is_set(lvp_bits, lvp_enum))
continue;
if (!(prop = get_lv_prop(lvp_enum)))
continue;
if (!prop->fn)
match = _lv_is_prop(cmd, lv, lvp_enum);
else
match = prop->fn(cmd, lv);
if (!match)
found_a_mismatch = 1;
if (match_bits && match)
*match_bits |= lvp_enum_to_bit(lvp_enum);
if (unmatch_bits && !match)
*unmatch_bits |= lvp_enum_to_bit(lvp_enum);
}
return !found_a_mismatch;
}
static int _check_lv_types(struct cmd_context *cmd, struct logical_volume *lv, int pos)
{
int ret = 1;
if (!pos)
return 1;
if (!cmd->command->required_pos_args[pos-1].def.lvt_bits)
return 1;
if (!val_bit_is_set(cmd->command->required_pos_args[pos-1].def.val_bits, lv_VAL)) {
log_error(INTERNAL_ERROR "Command (%s %d) arg position %d does not permit an LV (%llx)",
cmd->command->command_line_id, cmd->command->command_line_enum,
pos, (unsigned long long)cmd->command->required_pos_args[pos-1].def.val_bits);
return 0;
}
ret = _lv_types_match(cmd, lv, cmd->command->required_pos_args[pos-1].def.lvt_bits, NULL, NULL);
if (!ret) {
int lvt_enum = get_lvt_enum(lv);
struct lv_types *type = get_lv_type(lvt_enum);
log_warn("Operation on LV %s which has invalid type %s.",
display_lvname(lv), type ? type->name : "unknown");
}
return ret;
}
/* Check if LV passes each rule specified in command definition. */
static int _check_lv_rules(struct cmd_context *cmd, struct logical_volume *lv)
{
char buf[64];
struct cmd_rule *rule;
struct lv_types *lvtype = NULL;
uint64_t lv_props_match_bits, lv_props_unmatch_bits;
uint64_t lv_types_match_bits, lv_types_unmatch_bits;
int opts_match_count, opts_unmatch_count;
int lvt_enum;
int ret = 1;
int i;
lvt_enum = get_lvt_enum(lv);
if (lvt_enum)
lvtype = get_lv_type(lvt_enum);
for (i = 0; i < cmd->command->rule_count; i++) {
rule = &cmd->command->rules[i];
/*
* RULE: <conditions> INVALID|REQUIRE <checks>
*
* If all the conditions apply to the command+LV, then
* the checks are performed. If all conditions are zero
* (!opts_count, !lvt_bits, !lvp_bits), then the check
* is always performed.
*
* Conditions:
*
* 1. options (opts): if any of the specified options are set,
* then the checks may apply.
*
* 2. LV types (lvt_bits): if any of the specified LV types
* match the LV, then the checks may apply.
*
* 3. LV properties (lvp_bits): if all of the specified
* LV properties match the LV, then the checks may apply.
*
* If conditions 1, 2, 3 all pass, then the checks apply.
*
* Checks:
*
* 1. options (check_opts):
* INVALID: if any of the specified options are set,
* then the command fails.
* REQUIRE: if any of the specified options are not set,
* then the command fails.
*
* 2. LV types (check_lvt_bits):
* INVALID: if any of the specified LV types match the LV,
* then the command fails.
* REQUIRE: if none of the specified LV types match the LV,
* then the command fails.
*
* 3. LV properties (check_lvp_bits):
* INVALID: if any of the specified LV properties match
* the LV, then the command fails.
* REQUIRE: if any of the specified LV properties do not match
* the LV, then the command fails.
*/
if (rule->opts_count && !opt_in_list_is_set(cmd, rule->opts, rule->opts_count, NULL, NULL))
continue;
/* If LV matches one type in lvt_bits, this returns 1. */
if (rule->lvt_bits && !_lv_types_match(cmd, lv, rule->lvt_bits, NULL, NULL))
continue;
/* If LV matches all properties in lvp_bits, this returns 1. */
if (rule->lvp_bits && !_lv_props_match(cmd, lv, rule->lvp_bits, NULL, NULL))
continue;
/*
* Check the options, LV types, LV properties.
*/
if (rule->check_opts)
opt_in_list_is_set(cmd, rule->check_opts, rule->check_opts_count,
&opts_match_count, &opts_unmatch_count);
if (rule->check_lvt_bits)
_lv_types_match(cmd, lv, rule->check_lvt_bits,
&lv_types_match_bits, &lv_types_unmatch_bits);
if (rule->check_lvp_bits)
_lv_props_match(cmd, lv, rule->check_lvp_bits,
&lv_props_match_bits, &lv_props_unmatch_bits);
/*
* Evaluate if the check results pass based on the rule.
* The options are checked again here because the previous
* option validation (during command matching) does not cover
* cases where the option is combined with conditions of LV types
* or properties.
*/
/* Fail if any invalid options are set. */
if (rule->check_opts && (rule->rule == RULE_INVALID) && opts_match_count) {
memset(buf, 0, sizeof(buf));
opt_array_to_str(cmd, rule->check_opts, rule->check_opts_count, buf, sizeof(buf));
log_warn("An invalid option is set: %s", buf);
ret = 0;
}
/* Fail if any required options are not set. */
if (rule->check_opts && (rule->rule == RULE_REQUIRE) && opts_unmatch_count) {
memset(buf, 0, sizeof(buf));
opt_array_to_str(cmd, rule->check_opts, rule->check_opts_count, buf, sizeof(buf));
log_warn("A required option is not set: %s", buf);
ret = 0;
}
/* Fail if the LV matches any of the invalid LV types. */
if (rule->check_lvt_bits && (rule->rule == RULE_INVALID) && lv_types_match_bits) {
log_warn("Command on LV %s with invalid type: %s",
display_lvname(lv), lvtype ? lvtype->name : "unknown");
ret = 0;
}
/* Fail if the LV does not match any of the required LV types. */
if (rule->check_lvt_bits && (rule->rule == RULE_REQUIRE) && !lv_types_match_bits) {
memset(buf, 0, sizeof(buf));
lvt_bits_to_str(rule->check_lvt_bits, buf, sizeof(buf));
log_warn("Command on LV %s with type %s does not match required type: %s",
display_lvname(lv), lvtype ? lvtype->name : "unknown", buf);
ret = 0;
}
/* Fail if the LV matches any of the invalid LV properties. */
if (rule->check_lvp_bits && (rule->rule == RULE_INVALID) && lv_props_match_bits) {
memset(buf, 0, sizeof(buf));
lvp_bits_to_str(lv_props_match_bits, buf, sizeof(buf));
log_warn("Command on LV %s with invalid properties: %s",
display_lvname(lv), buf);
ret = 0;
}
/* Fail if the LV does not match any of the required LV properties. */
if (rule->check_lvp_bits && (rule->rule == RULE_REQUIRE) && lv_props_unmatch_bits) {
memset(buf, 0, sizeof(buf));
lvp_bits_to_str(lv_props_unmatch_bits, buf, sizeof(buf));
log_warn("Command on LV %s requires properties: %s",
display_lvname(lv), buf);
ret = 0;
}
}
return ret;
}
/*
* Return which arg position the given LV is at,
* where 1 represents the first position arg.
* When the first position arg is repeatable,
* return 1 for all.
*
* Return 0 when the command has no required
* position args. (optional position args are
* not considered.)
*/
static int _find_lv_arg_position(struct cmd_context *cmd, struct logical_volume *lv)
{
const char *sep, *lvname;
int i;
if (cmd->command->rp_count == 0)
return 0;
if (cmd->command->rp_count == 1)
return 1;
for (i = 0; i < cmd->position_argc; i++) {
if (i == cmd->command->rp_count)
break;
if (!val_bit_is_set(cmd->command->required_pos_args[i].def.val_bits, lv_VAL))
continue;
if ((sep = strstr(cmd->position_argv[i], "/")))
lvname = sep + 1;
else
lvname = cmd->position_argv[i];
if (!strcmp(lvname, lv->name))
return i + 1;
}
/*
* If the last position arg is an LV and this
* arg is beyond that position, then the last
* LV position arg is repeatable, so return
* that position.
*/
if (i == cmd->command->rp_count) {
int last_pos = cmd->command->rp_count;
if (val_bit_is_set(cmd->command->required_pos_args[last_pos-1].def.val_bits, lv_VAL))
return last_pos;
}
return 0;
}
int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
struct dm_list *arg_lvnames, const struct dm_list *tags_in,
int stop_on_error,
struct processing_handle *handle,
check_single_lv_fn_t check_single_lv,
process_single_lv_fn_t process_single_lv)
{
log_report_t saved_log_report_state = log_get_report_state();
@@ -2938,13 +2345,10 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
unsigned process_all = 0;
unsigned tags_supplied = 0;
unsigned lvargs_supplied = 0;
int lv_is_named_arg;
int lv_arg_pos;
struct lv_list *lvl;
struct dm_str_list *sl;
struct dm_list final_lvs;
struct lv_list *final_lvl;
struct dm_list found_arg_lvnames;
struct glv_list *glvl, *tglvl;
int do_report_ret_code = 1;
@@ -2955,7 +2359,6 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
stack;
dm_list_init(&final_lvs);
dm_list_init(&found_arg_lvnames);
if (!vg_check_status(vg, EXPORTED_VG)) {
ret_max = ECMD_FAILED;
@@ -3049,7 +2452,6 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
if (lvargs_supplied && str_list_match_item(arg_lvnames, lvl->lv->name)) {
/* Remove LV from list of unprocessed LV names */
str_list_del(arg_lvnames, lvl->lv->name);
str_list_add(cmd->mem, &found_arg_lvnames, lvl->lv->name);
process_lv = 1;
}
@@ -3097,43 +2499,6 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
if (lv_is_removed(lvl->lv))
continue;
lv_is_named_arg = str_list_match_item(&found_arg_lvnames, lvl->lv->name);
lv_arg_pos = _find_lv_arg_position(cmd, lvl->lv);
/*
* The command definition may include restrictions on the
* types and properties of LVs that can be processed.
*/
if (!_check_lv_types(cmd, lvl->lv, lv_arg_pos)) {
/* FIXME: include this result in report log? */
if (lv_is_named_arg) {
log_error("Operation not permitted (%s %d) on LV %s.",
cmd->command->command_line_id, cmd->command->command_line_enum,
display_lvname(lvl->lv));
ret_max = ECMD_FAILED;
}
continue;
}
if (!_check_lv_rules(cmd, lvl->lv)) {
/* FIXME: include this result in report log? */
if (lv_is_named_arg) {
log_error("Operation not permitted (%s %d) on LV %s.",
cmd->command->command_line_id, cmd->command->command_line_enum,
display_lvname(lvl->lv));
ret_max = ECMD_FAILED;
}
continue;
}
if (check_single_lv && !check_single_lv(cmd, lvl->lv, handle, lv_is_named_arg)) {
if (lv_is_named_arg)
ret_max = ECMD_FAILED;
continue;
}
log_very_verbose("Processing LV %s in VG %s.", lvl->lv->name, vg->name);
ret = process_single_lv(cmd, lvl->lv, handle);
@@ -3364,164 +2729,12 @@ static int _get_arg_lvnames(struct cmd_context *cmd,
return ret_max;
}
/*
* This is a non-standard way of finding vgname/lvname to process. It exists
* because an earlier form of lvconvert did not follow the standard form, and
* came up with its own inconsistent approach.
*
* In this case, when the position arg is a single name, it is treated as an LV
* name (not a VG name). This leaves the VG unknown. So, other option values
* must be searched for a VG name. If one of those option values contains a
* vgname/lvname value, then the VG name is extracted and used for the LV
* position arg.
*
* Other option values that are searched for a VG name are:
* --thinpool, --cachepool.
*
* . command vg/lv1
* . add vg to arg_vgnames
* . add vg/lv1 to arg_lvnames
*
* command lv1
* . error: no vg name
*
* command --option vg/lv1 vg/lv2
* . verify both vg names match
* . add vg to arg_vgnames
* . add vg/lv2 to arg_lvnames
*
* command --option lv1 lv2
* . error: no vg name
*
* command --option vg/lv1 lv2
* . add vg to arg_vgnames
* . add vg/lv2 to arg_lvnames
*
* command --option lv1 vg/lv2
* . add vg to arg_vgnames
* . add vg/lv2 to arg_lvnames
*/
static int _get_arg_lvnames_using_options(struct cmd_context *cmd,
int argc, char **argv,
struct dm_list *arg_vgnames,
struct dm_list *arg_lvnames,
struct dm_list *arg_tags)
{
const char *pos_name = NULL;
const char *arg_name = NULL;
const char *pos_vgname = NULL;
const char *opt_vgname = NULL;
const char *pos_lvname = NULL;
const char *use_vgname = NULL;
char *tmp_name;
char *split;
char *vglv;
size_t vglv_sz;
if (argc != 1) {
log_error("One LV position arg is required.");
return ECMD_FAILED;
}
if (!(pos_name = dm_pool_strdup(cmd->mem, argv[0]))) {
log_error("string alloc failed.");
return ECMD_FAILED;
}
if (*pos_name == '@') {
if (!validate_tag(pos_name + 1)) {
log_error("Skipping invalid tag %s.", pos_name);
return ECMD_FAILED;
}
if (!str_list_add(cmd->mem, arg_tags,
dm_pool_strdup(cmd->mem, pos_name + 1))) {
log_error("strlist allocation failed.");
return ECMD_FAILED;
}
return ECMD_PROCESSED;
}
if ((split = strchr(pos_name, '/'))) {
pos_vgname = pos_name;
pos_lvname = split + 1;
*split = '\0';
} else {
pos_lvname = pos_name;
pos_vgname = NULL;
}
if (arg_is_set(cmd, thinpool_ARG))
arg_name = arg_str_value(cmd, thinpool_ARG, NULL);
else if (arg_is_set(cmd, cachepool_ARG))
arg_name = arg_str_value(cmd, cachepool_ARG, NULL);
if (!pos_vgname && !arg_name) {
log_error("Cannot find VG name for LV %s.", pos_lvname);
return ECMD_FAILED;
}
if (arg_name && (split = strchr(arg_name, '/'))) {
/* combined VG/LV */
if (!(tmp_name = dm_pool_strdup(cmd->mem, arg_name))) {
log_error("string alloc failed.");
return ECMD_FAILED;
}
if (!(split = strchr(tmp_name, '/')))
return ECMD_FAILED;
opt_vgname = tmp_name;
/* Don't care about opt lvname. */
/* opt_lvname = split + 1; */
*split = '\0';
} else {
/* Don't care about opt lvname. */
/* opt_lvname = arg_name; */
opt_vgname = NULL;
}
if (!pos_vgname && !opt_vgname) {
log_error("Cannot find VG name for LV %s.", pos_lvname);
return ECMD_FAILED;
}
if (pos_vgname && opt_vgname && strcmp(pos_vgname, opt_vgname)) {
log_error("VG name mismatch from position arg (%s) and option arg (%s).",
pos_vgname, opt_vgname);
return ECMD_FAILED;
}
use_vgname = pos_vgname ? pos_vgname : opt_vgname;
if (!str_list_add(cmd->mem, arg_vgnames, dm_pool_strdup(cmd->mem, use_vgname))) {
log_error("strlist allocation failed.");
return ECMD_FAILED;
}
vglv_sz = strlen(use_vgname) + strlen(pos_lvname) + 2;
if (!(vglv = dm_pool_alloc(cmd->mem, vglv_sz)) ||
dm_snprintf(vglv, vglv_sz, "%s/%s", use_vgname, pos_lvname) < 0) {
log_error("vg/lv string alloc failed.");
return ECMD_FAILED;
}
if (!str_list_add(cmd->mem, arg_lvnames, vglv)) {
log_error("strlist allocation failed.");
return ECMD_FAILED;
}
return ECMD_PROCESSED;
}
static int _process_lv_vgnameid_list(struct cmd_context *cmd, uint32_t read_flags,
struct dm_list *vgnameids_to_process,
struct dm_list *arg_vgnames,
struct dm_list *arg_lvnames,
struct dm_list *arg_tags,
struct processing_handle *handle,
check_single_lv_fn_t check_single_lv,
process_single_lv_fn_t process_single_lv)
{
log_report_t saved_log_report_state = log_get_report_state();
@@ -3614,7 +2827,7 @@ static int _process_lv_vgnameid_list(struct cmd_context *cmd, uint32_t read_flag
goto endvg;
ret = process_each_lv_in_vg(cmd, vg, &lvnames, tags_arg, 0,
handle, check_single_lv, process_single_lv);
handle, process_single_lv);
if (ret != ECMD_PROCESSED)
stack;
report_log_ret_code(ret);
@@ -3645,7 +2858,6 @@ int process_each_lv(struct cmd_context *cmd,
const char *one_vgname, const char *one_lvname,
uint32_t read_flags,
struct processing_handle *handle,
check_single_lv_fn_t check_single_lv,
process_single_lv_fn_t process_single_lv)
{
log_report_t saved_log_report_state = log_get_report_state();
@@ -3674,12 +2886,7 @@ int process_each_lv(struct cmd_context *cmd,
/*
* Find any LVs, VGs or tags explicitly provided on the command line.
*/
if (cmd->command->flags & GET_VGNAME_FROM_OPTIONS)
ret = _get_arg_lvnames_using_options(cmd, argc, argv, &arg_vgnames, &arg_lvnames, &arg_tags);
else
ret = _get_arg_lvnames(cmd, argc, argv, one_vgname, one_lvname, &arg_vgnames, &arg_lvnames, &arg_tags);
if (ret != ECMD_PROCESSED) {
if ((ret = _get_arg_lvnames(cmd, argc, argv, one_vgname, one_lvname, &arg_vgnames, &arg_lvnames, &arg_tags) != ECMD_PROCESSED)) {
ret_max = ret;
goto_out;
}
@@ -3766,7 +2973,7 @@ int process_each_lv(struct cmd_context *cmd,
_choose_vgs_to_process(cmd, &arg_vgnames, &vgnameids_on_system, &vgnameids_to_process);
ret = _process_lv_vgnameid_list(cmd, read_flags, &vgnameids_to_process, &arg_vgnames, &arg_lvnames,
&arg_tags, handle, check_single_lv, process_single_lv);
&arg_tags, handle, process_single_lv);
if (ret > ret_max)
ret_max = ret;
@@ -4728,6 +3935,11 @@ int pvcreate_params_from_args(struct cmd_context *cmd, struct pvcreate_params *p
if (pp->pva.pvmetadatacopies < 0)
pp->pva.pvmetadatacopies = find_config_tree_int(cmd, metadata_pvmetadatacopies_CFG, NULL);
if (pp->pva.pvmetadatacopies > 2) {
log_error("Metadatacopies may only be 0, 1 or 2");
return 0;
}
pp->pva.ba_size = arg_uint64_value(cmd, bootloaderareasize_ARG, pp->pva.ba_size);
return 1;

View File

@@ -98,18 +98,6 @@ typedef int (*process_single_pvseg_fn_t) (struct cmd_context * cmd,
struct pv_segment * pvseg,
struct processing_handle *handle);
/*
* Called prior to process_single_lv() to decide if the LV should be
* processed. If this returns 0, the LV is not processed.
*
* This can evaluate the combination of command definition and
* the LV object to decide if the combination is allowed.
*/
typedef int (*check_single_lv_fn_t) (struct cmd_context *cmd,
struct logical_volume *lv,
struct processing_handle *handle,
int lv_is_named_arg);
int process_each_vg(struct cmd_context *cmd,
int argc, char **argv,
const char *one_vgname,
@@ -137,7 +125,6 @@ int process_each_segment_in_pv(struct cmd_context *cmd,
int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
const char *one_vgname, const char *one_lvname,
uint32_t flags, struct processing_handle *handle,
check_single_lv_fn_t check_single_lv,
process_single_lv_fn_t process_single_lv);
@@ -154,7 +141,6 @@ int process_each_pv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
struct dm_list *arg_lvnames, const struct dm_list *tagsl,
int stop_on_error, struct processing_handle *handle,
check_single_lv_fn_t check_single_lv,
process_single_lv_fn_t process_single_lv);
struct processing_handle *init_processing_handle(struct cmd_context *cmd, struct processing_handle *parent_handle);
@@ -173,12 +159,6 @@ const char *extract_vgname(struct cmd_context *cmd, const char *lv_name);
const char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name,
unsigned *dev_dir_found);
int opt_in_list_is_set(struct cmd_context *cmd, int *opts, int count,
int *match_count, int *unmatch_count);
void opt_array_to_str(struct cmd_context *cmd, int *opts, int count,
char *buf, int len);
int pvcreate_params_from_args(struct cmd_context *cmd, struct pvcreate_params *pp);
int pvcreate_each_device(struct cmd_context *cmd, struct processing_handle *handle, struct pvcreate_params *pp);
@@ -240,6 +220,4 @@ int validate_restricted_lvname_param(struct cmd_context *cmd, const char **vg_na
int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv,
struct processing_handle *handle __attribute__((unused)));
int get_lvt_enum(struct logical_volume *lv);
#endif

View File

@@ -50,41 +50,20 @@
#define CMD_LEN 256
#define MAX_ARGS 64
/* define the enums for the values accepted by command line --options, foo_VAL */
enum {
#define val(a, b, c, d) a ,
#include "vals.h"
#undef val
};
/* define the enums for the command line --options, foo_ARG */
enum {
#define arg(a, b, c, d, e, f, g) a ,
#include "args.h"
#undef arg
};
/* command functions */
typedef int (*command_fn) (struct cmd_context * cmd, int argc, char **argv);
#define xx(a, b...) int a(struct cmd_context *cmd, int argc, char **argv);
#include "commands.h"
#undef xx
/* define enums for LV properties, foo_LVP */
/* define the enums for the command line switches */
enum {
#define lvp(a, b, c) a ,
#include "lv_props.h"
#undef lvp
#define arg(a, b, c, d, e, f) a ,
#include "args.h"
#undef arg
};
/* define enums for LV types, foo_LVT */
enum {
#define lvt(a, b, c) a ,
#include "lv_types.h"
#undef lvt
};
#include "command.h"
#define ARG_COUNTABLE 0x00000001 /* E.g. -vvvv */
#define ARG_GROUPABLE 0x00000002 /* E.g. --addtag */
@@ -100,16 +79,15 @@ struct arg_values {
/* void *ptr; // Currently not used. */
};
/* a global table of possible --option's */
/* a global table of possible arguments */
struct arg_props {
int arg_enum; /* foo_ARG from args.h */
const char short_arg;
char _padding[7];
const char *long_arg;
int val_enum; /* foo_VAL from vals.h */
int (*fn) (struct cmd_context *cmd, struct arg_values *av);
uint32_t flags;
uint32_t prio;
const char *desc;
};
struct arg_value_group_list {
@@ -118,29 +96,6 @@ struct arg_value_group_list {
uint32_t prio;
};
/* a global table of possible --option values */
struct val_props {
int val_enum; /* foo_VAL from vals.h */
int (*fn) (struct cmd_context *cmd, struct arg_values *av);
const char *name;
const char *usage;
};
/* a global table of possible LV properties */
struct lv_props {
int lvp_enum; /* is_foo_LVP from lv_props.h */
const char *name; /* "lv_is_foo" used in command-lines.in */
int (*fn) (struct cmd_context *cmd, struct logical_volume *lv); /* lv_is_foo() */
};
/* a global table of possible LV types */
/* (as exposed externally in command line interface, not exactly as internal segtype is used) */
struct lv_types {
int lvt_enum; /* is_foo_LVT from lv_types.h */
const char *name; /* "foo" used in command-lines.in, i.e. LV_foo */
int (*fn) (struct cmd_context *cmd, struct logical_volume *lv); /* lv_is_foo() */
};
#define CACHE_VGMETADATA 0x00000001
#define PERMITTED_READ_ONLY 0x00000002
/* Process all VGs if none specified on the command line. */
@@ -163,8 +118,19 @@ struct lv_types {
#define ENABLE_DUPLICATE_DEVS 0x00000400
/* Command does not accept tags as args. */
#define DISALLOW_TAG_ARGS 0x00000800
/* Command may need to find VG name in an option value. */
#define GET_VGNAME_FROM_OPTIONS 0x00001000
/* a register of the lvm commands */
struct command {
const char *name;
const char *desc;
const char *usage;
command_fn fn;
unsigned flags;
int num_args;
int *valid_args;
};
void usage(const char *name);
@@ -192,15 +158,7 @@ int segtype_arg(struct cmd_context *cmd, struct arg_values *av);
int alloc_arg(struct cmd_context *cmd, struct arg_values *av);
int locktype_arg(struct cmd_context *cmd, struct arg_values *av);
int readahead_arg(struct cmd_context *cmd, struct arg_values *av);
int vgmetadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
int pvmetadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
int metadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
int polloperation_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
int writemostly_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
int syncaction_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
int reportformat_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
int configreport_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
int configtype_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
/* we use the enums to access the switches */
unsigned arg_count(const struct cmd_context *cmd, int a);
@@ -242,41 +200,4 @@ int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg,
int vgchange_background_polling(struct cmd_context *cmd, struct volume_group *vg);
struct lv_props *get_lv_prop(int lvp_enum);
struct lv_types *get_lv_type(int lvt_enum);
struct command *get_command(int cmd_enum);
int lvchange_properties_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvchange_activate_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvchange_refresh_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvchange_resync_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvchange_syncaction_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvchange_rebuild_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvchange_monitor_poll_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvchange_persistent_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvconvert_repair_pvs_or_thinpool_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvconvert_replace_pv_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvconvert_merge_snapshot_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvconvert_split_snapshot_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvconvert_combine_split_snapshot_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvconvert_start_poll_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvconvert_to_pool_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvconvert_to_pool_noarg_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvconvert_to_cache_vol_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvconvert_to_thin_with_external_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvconvert_swap_pool_metadata_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvconvert_merge_thin_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvconvert_split_cachepool_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvconvert_raid_types_cmd(struct cmd_context * cmd, int argc, char **argv);
int lvconvert_split_mirror_images_cmd(struct cmd_context * cmd, int argc, char **argv);
int lvconvert_merge_mirror_images_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvconvert_change_mirrorlog_cmd(struct cmd_context * cmd, int argc, char **argv);
int lvconvert_merge_cmd(struct cmd_context *cmd, int argc, char **argv);
#endif

View File

@@ -1,137 +0,0 @@
/*
* Define value types which describe values accepted
* by the --option's in args.h, and can also describe
* the values accepted as positional args.
*
* Previously, accepted values were only "described"
* by identifying the parsing function to use.
*
* Some standard val types are used by many options,
* e.g. many options (aa_ARG, bb_ARG, cc_ARG) all
* accept a number_VAL.
*
* Other special val types are used by only one option,
* e.g. only mirrorlog_ARG accepts a mirrorlog_VAL.
* This typically means that there are some specific
* words that are recognized after the option.
*
* Some options currently take a standard val type,
* (esp string_VAL), but they could be given their
* own custom val type. The advantage of using a
* custom val type is the possibility of validating
* the value when parsing it with a custom parsing
* function, and the possibility of displaying the
* actual accepted values in the command usage.
* Without a custom val type, the code must do ad hoc
* validation of the string values, and the usage
* output for the option will only say "String"
* rather than giving the accepted string values.
* Even without a custom parsing function, there is
* reason to define a custom x_VAL enum so that a
* more descriptive usage string can be specified
* as opposed to just "String".
*
* Most of the val types defined here are used after
* --option's, and are referenced in foo_ARG entries
* in args.h. But, some val types are only used to
* represent positional values in command definitions,
* e.g. vg_VAL.
*
* val(a, b, c, d)
*
* a: foo_VAL enums
* b: the function to parse and set the value
* c: the name used to reference this value in command defs
* d: what to display in usage output for this value
*
* command defintions will use --option NAME, where NAME
* is shown in val() field c. NAME will be translated to
* foo_VAL enum in field a, which is used in commands[]
* structs.
*
* option definitions (arg.h) will reference foo_VAL enum
* in field a.
*
* FIXME: for specialized val types, the set of recognized
* words is not defined or stored in a consistent way,
* but is just whatever the parsing function happens to look
* for, so adding a new accepted value for the val type is
* generally making the parsing function recognize a new
* word, and making the implementation code also recognize
* that word to do something different. This new word should
* then also be added to the usage string for the val type here.
* It would be nice if the accepted values could be defined in a
* more consistent way, and perhaps in a single place, perhaps in
* struct val_props.
*
* The usage text for an option is not always the full
* set of words accepted for an option, but may be a
* subset. i.e. an outdated word that no longer does
* anything may not be shown, but may still be recognized
* and ignored, or an option that shouldn't be used in
* general isn't shown to avoid suggesting it.
* e.g. for --activate we show the most common "y|n|ay"
* without showing the lvmlockd variations "ey|sy" which
* are not applicable in general.
*
* FIXME: are there some specialized or irrelevant
* options included in the usage text below that should
* be removed? Should "lvm1" be removed?
*
* For Number args that take optional units, a full usage
* could be "Number[bBsSkKmMgGtTpPeE]" (with implied |),
* but repeating this full specification produces cluttered
* output, and doesn't indicate which unit is the default.
* "Number[units]" would be cleaner, as would a subset of
* common units, e.g. "Number[kmg...]", but neither helps
* with default. "Number[k|unit]" and "Number[m|unit]" show
* the default, and "unit" indicates that other units
* are possible without listing them all. This also
* suggests using the preferred lower case letters, because
* --size and other option args treat upper/lower letters
* the same, all as 1024 SI base. For this reason, we
* should avoid suggesting the upper case letters.
*/
val(none_VAL, NULL, "None", "ERR") /* unused, for enum value 0 */
val(conststr_VAL, NULL, "ConstString", "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(number_VAL, int_arg, "Number", NULL)
val(uint32_VAL, uint32_arg, "Uint32", "Number")
val(string_VAL, string_arg, "String", NULL)
val(vg_VAL, string_arg, "VG", NULL)
val(lv_VAL, string_arg, "LV", NULL)
val(pv_VAL, string_arg, "PV", NULL)
val(tag_VAL, tag_arg, "Tag", NULL)
val(select_VAL, NULL, "Select", NULL) /* used only for command defs */
val(activationmode_VAL, string_arg, "ActivationMode", "partial|degraded|complete")
val(activation_VAL, activation_arg, "Active", "y|n|ay")
val(cachemode_VAL, cachemode_arg, "CacheMode", "writethrough|writeback")
val(discards_VAL, discards_arg, "Discards", "passdown|nopassdown|ignore")
val(mirrorlog_VAL, mirrorlog_arg, "MirrorLog", "core|disk")
val(sizekb_VAL, size_kb_arg, "SizeKB", "Number[k|unit]")
val(sizemb_VAL, size_mb_arg, "SizeMB", "Number[m|unit]")
val(numsigned_VAL, int_arg_with_sign, "SNumber", "[+|-]Number")
val(numsignedper_VAL, int_arg_with_sign_and_percent, "SNumberP", "[+|-]Number[%VG|%PVS|%FREE]")
val(permission_VAL, permission_arg, "Permission", "rw|r")
val(metadatatype_VAL, metadatatype_arg, "MetadataType", "lvm2|lvm1")
val(units_VAL, string_arg, "Units", "hHbBsSkKmMgGtTpPeE")
val(segtype_VAL, segtype_arg, "SegType", "linear|striped|snapshot|mirror|raid*|thin|cache|thin-pool|cache-pool")
val(alloc_VAL, alloc_arg, "Alloc", "contiguous|cling|cling_by_tags|normal|anywhere|inherit")
val(locktype_VAL, locktype_arg, "LockType", "sanlock|dlm|none")
val(readahead_VAL, readahead_arg, "Readahead", "auto|none|NumberSectors")
val(vgmetadatacopies_VAL, vgmetadatacopies_arg, "MetadataCopiesVG", "all|unmanaged|Number")
val(pvmetadatacopies_VAL, pvmetadatacopies_arg, "MetadataCopiesPV", "0|1|2")
val(metadatacopies_VAL, metadatacopies_arg, "unused", "unused")
val(polloperation_VAL, polloperation_arg, "PollOp", "pvmove|convert|merge|merge_thin")
val(writemostly_VAL, writemostly_arg, "WriteMostlyPV", "PV[:t|n|y]")
val(syncaction_VAL, syncaction_arg, "SyncAction", "check|repair")
val(reportformat_VAL, reportformat_arg, "ReportFmt", "basic|json")
val(configreport_VAL, configreport_arg, "ConfigReport", "log|vg|lv|pv|pvseg|seg")
val(configtype_VAL, configtype_arg, "ConfigType", "current|default|diff|full|list|missing|new|profilable|profilable-command|profilable-metadata")
/* this should always be last */
val(VAL_COUNT, NULL, NULL, NULL)

View File

@@ -482,9 +482,6 @@ static int _vgchange_metadata_copies(struct cmd_context *cmd,
{
uint32_t mda_copies = arg_uint_value(cmd, vgmetadatacopies_ARG, DEFAULT_VGMETADATACOPIES);
log_warn("vgchange_metadata_copies new %u vg_mda_copies %u D %u",
mda_copies, vg_mda_copies(vg), DEFAULT_VGMETADATACOPIES);
if (mda_copies == vg_mda_copies(vg)) {
if (vg_mda_copies(vg) == VGMETADATACOPIES_UNMANAGED)
log_warn("Number of metadata copies for VG %s is already unmanaged.",

View File

@@ -157,12 +157,24 @@ int vgconvert(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
if (arg_is_set(cmd, metadatacopies_ARG)) {
log_error("Invalid option --metadatacopies, "
"use --pvmetadatacopies instead.");
return EINVALID_CMD_LINE;
}
if (!(cmd->fmt->features & FMT_MDAS) &&
arg_is_set(cmd, pvmetadatacopies_ARG)) {
(arg_is_set(cmd, pvmetadatacopies_ARG) ||
arg_is_set(cmd, metadatasize_ARG))) {
log_error("Metadata parameters only apply to text format");
return EINVALID_CMD_LINE;
}
if (arg_is_set(cmd, pvmetadatacopies_ARG) &&
arg_int_value(cmd, pvmetadatacopies_ARG, -1) > 2) {
log_error("Metadatacopies may only be 0, 1 or 2");
return EINVALID_CMD_LINE;
}
if (!(cmd->fmt->features & FMT_BAS) &&
arg_is_set(cmd, bootloaderareasize_ARG)) {
log_error("Bootloader area parameters only apply to text format");

View File

@@ -38,7 +38,7 @@ static int vgdisplay_single(struct cmd_context *cmd, const char *vg_name,
vgdisplay_extents(vg);
process_each_lv_in_vg(cmd, vg, NULL, NULL, 0, NULL,
NULL, (process_single_lv_fn_t)lvdisplay_full);
(process_single_lv_fn_t)lvdisplay_full);
log_print("--- Physical volumes ---");
process_each_pv_in_vg(cmd, vg, NULL,

View File

@@ -136,6 +136,12 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
if (arg_is_set(cmd, metadatacopies_ARG)) {
log_error("Invalid option --metadatacopies, "
"use --pvmetadatacopies instead.");
return EINVALID_CMD_LINE;
}
vg_name = skip_dev_dir(cmd, argv[0], NULL);
argc--;
argv++;

View File

@@ -33,5 +33,5 @@ int vgmknodes(struct cmd_context *cmd, int argc, char **argv)
if (!lv_mknodes(cmd, NULL))
return_ECMD_FAILED;
return process_each_lv(cmd, argc, argv, NULL, NULL, LCK_VG_READ, NULL, NULL, &_vgmknodes_single);
return process_each_lv(cmd, argc, argv, NULL, NULL, LCK_VG_READ, NULL, &_vgmknodes_single);
}

View File

@@ -62,7 +62,7 @@ static int vgremove_single(struct cmd_context *cmd, const char *vg_name,
}
if ((ret = process_each_lv_in_vg(cmd, vg, NULL, NULL, 1, &void_handle,
NULL, (process_single_lv_fn_t)lvremove_single)) != ECMD_PROCESSED) {
(process_single_lv_fn_t)lvremove_single)) != ECMD_PROCESSED) {
stack;
return ret;
}