1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-09-28 09:44:18 +03:00

Compare commits

..

1 Commits

Author SHA1 Message Date
David Teigland
7f02163489 commands: new method for defining commands
. Define a prototype for every lvm command.
. Match every user command with one definition.
. Generate help text and man pages from them.

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

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

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

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

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

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

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

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

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

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

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

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

$ lvresize --help
  lvresize - Resize a logical volume

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

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

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

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

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

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

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

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

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

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

So, this first phase validates every user-entered command
against the set of command prototypes, then calls the existing
implementation.  The second phase can associate an implementation
function with each definition, and take further advantage of the
known operation to avoid the complicated option analysis.
2016-10-27 15:57:27 -05:00
76 changed files with 2055 additions and 3564 deletions

View File

@@ -1 +1 @@
2.02.168(2)-git (2016-11-05)
2.02.167(2)-git (2016-09-26)

View File

@@ -1 +1 @@
1.02.137-git (2016-11-05)
1.02.136-git (2016-09-26)

View File

@@ -1,18 +1,5 @@
Version 2.02.168 -
====================================
Only log msg as debug if lvm2-lvmdbusd unit missing for D-Bus notification.
Missing stripe filler now could be also 'zero'.
lvconvert --repair accepts --interval and --background option.
More efficiently prepare _rmeta devices when creating a new raid LV.
Version 2.02.167 - 5th November 2016
====================================
Use log_error in regex and sysfs filter to describe reason of failure.
Fix blkdeactivate to deactivate dev stack if dev on top already unmounted.
Prevent non-synced raid1 repair unless --force
Prevent raid4 creation/conversion on non-supporting kernels
Add direct striped -> raid4 conversion
Fix raid4 parity image pair position on conversions from striped/raid0*
Version 2.02.167 -
======================================
Fix a few unconverted return code values for some lvconvert error path.
Disable lvconvert of thin pool to raid while active.
Disable systemd service start rate limiting for lvm2-pvscan@.service.

View File

@@ -1,16 +1,5 @@
Version 1.02.137 -
====================================
Version 1.02.136 - 5th November 2016
====================================
Log failure of raid device with log_error level.
Use dm_log_with_errno and translate runtime to dm_log only when needed.
Make log messages from dm and lvm library different from dmeventd.
Notice and Info messages are again logged from dmeventd and its plugins.
Dmeventd now also respects DM_ABORT_ON_INTERNAL_ERRORS as libdm based tool.
Report as non default dm logging also when logging with errno was changed.
Use log_level() macro to consistently decode message log level in dmeventd.
Still produce output when dmsetup dependency tree building finds dev missing.
Version 1.02.136 -
======================================
Check and report pthread_sigmask() failure in dmeventd.
Check mem alloc fail in _canonicalize_field_ids().
Use unsigned math when checking more then 31 legs of raid.

View File

@@ -99,28 +99,13 @@ static time_t _idle_since = 0;
static char **_initial_registrations = 0;
/* FIXME Make configurable at runtime */
/* All libdm messages */
__attribute__((format(printf, 5, 6)))
static void _libdm_log(int level, const char *file, int line,
int dm_errno_or_class, const char *format, ...)
{
va_list ap;
va_start(ap, format);
dm_event_log("#dm", level, file, line, dm_errno_or_class, format, ap);
va_end(ap);
}
/* All dmeventd messages */
#undef LOG_MESG
#define LOG_MESG(l, f, ln, e, x...) _dmeventd_log(l, f, ln, e, ## x)
__attribute__((format(printf, 5, 6)))
__attribute__((format(printf, 4, 5)))
static void _dmeventd_log(int level, const char *file, int line,
int dm_errno_or_class, const char *format, ...)
const char *format, ...)
{
va_list ap;
va_start(ap, format);
dm_event_log("dmeventd", level, file, line, dm_errno_or_class, format, ap);
dm_event_log("dm", level, file, line, 0, format, ap);
va_end(ap);
}
@@ -2206,7 +2191,7 @@ int main(int argc, char *argv[])
openlog("dmeventd", LOG_PID, LOG_DAEMON);
dm_event_log_set(_debug_level, _use_syslog);
dm_log_with_errno_init(_libdm_log);
dm_log_init(_dmeventd_log);
(void) dm_prepare_selinux_context(DMEVENTD_PIDFILE, S_IFREG);
if (dm_create_lockfile(DMEVENTD_PIDFILE) == 0)

View File

@@ -865,38 +865,28 @@ void dm_event_log(const char *subsys, int level, const char *file,
int line, int dm_errno_or_class,
const char *format, va_list ap)
{
static int _abort_on_internal_errors = -1;
static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER;
static time_t start = 0;
const char *indent = "";
FILE *stream = log_stderr(level) ? stderr : stdout;
FILE *stream = stdout;
int prio;
time_t now;
int log_with_debug = 0;
if (subsys[0] == '#') {
/* Subsystems starting with '#' are logged
* only when debugging is enabled. */
log_with_debug++;
subsys++;
}
switch (log_level(level)) {
switch (level & ~(_LOG_STDERR | _LOG_ONCE)) {
case _LOG_DEBUG:
/* Never shown without -ddd */
if (_debug_level < 3)
return;
prio = LOG_DEBUG;
indent = " ";
break;
case _LOG_INFO:
if (log_with_debug && _debug_level < 2)
if (_debug_level < 2)
return;
prio = LOG_INFO;
indent = " ";
break;
case _LOG_NOTICE:
if (log_with_debug && _debug_level < 1)
if (_debug_level < 1)
return;
prio = LOG_NOTICE;
indent = " ";
@@ -922,13 +912,12 @@ void dm_event_log(const char *subsys, int level, const char *file,
if (!start)
start = now;
now -= start;
if (_debug_level)
fprintf(stream, "[%2d:%02d] %8x:%-6s%s",
(int)now / 60, (int)now % 60,
// TODO: Maybe use shorter ID
// ((int)(pthread_self()) >> 6) & 0xffff,
(int)pthread_self(), subsys,
(_debug_level > 3) ? "" : indent);
fprintf(stream, "[%2d:%02d] %8x:%-6s%s",
(int)now / 60, (int)now % 60,
// TODO: Maybe use shorter ID
// ((int)(pthread_self()) >> 6) & 0xffff,
(int)pthread_self(), subsys,
(_debug_level > 3) ? "" : indent);
if (_debug_level > 3)
fprintf(stream, "%28s:%4d %s", file, line, indent);
vfprintf(stream, _(format), ap);
@@ -937,15 +926,6 @@ void dm_event_log(const char *subsys, int level, const char *file,
}
pthread_mutex_unlock(&_log_mutex);
if (_abort_on_internal_errors < 0)
/* Set when env DM_ABORT_ON_INTERNAL_ERRORS is not "0" */
_abort_on_internal_errors =
strcmp(getenv("DM_ABORT_ON_INTERNAL_ERRORS") ? : "0", "0");
if (_abort_on_internal_errors &&
!strncmp(format, INTERNAL_ERROR, sizeof(INTERNAL_ERROR) - 1))
abort();
}
#if 0 /* left out for now */

View File

@@ -32,7 +32,7 @@ static int _register_count = 0;
static struct dm_pool *_mem_pool = NULL;
static void *_lvm_handle = NULL;
DM_EVENT_LOG_FN("#lvm")
DM_EVENT_LOG_FN("lvm")
static void _lvm2_print_log(int level, const char *file, int line,
int dm_errno_or_class, const char *msg)

View File

@@ -73,10 +73,8 @@ static int _get_mirror_event(struct dso_state *state, char *params)
unsigned i;
struct dm_status_mirror *ms;
if (!dm_get_status_mirror(state->mem, params, &ms)) {
log_error("Unable to parse mirror status string.");
return ME_IGNORE;
}
if (!dm_get_status_mirror(state->mem, params, &ms))
goto_out;
/* Check for bad mirror devices */
for (i = 0; i < ms->dev_count; ++i)
@@ -97,23 +95,27 @@ static int _get_mirror_event(struct dso_state *state, char *params)
dm_pool_free(state->mem, ms);
return r;
out:
log_error("Unable to parse mirror status string.");
return ME_IGNORE;
}
static int _remove_failed_devices(const char *cmd_lvscan, const char *cmd_lvconvert,
const char *device)
static int _remove_failed_devices(const char *cmd_lvscan, const char *cmd_lvconvert)
{
int r;
if (!dmeventd_lvm2_run_with_lock(cmd_lvscan))
log_warn("WARNING: Re-scan of mirrored device %s failed.", device);
log_info("Re-scan of mirrored device failed.");
/* if repair goes OK, report success even if lvscan has failed */
if (!dmeventd_lvm2_run_with_lock(cmd_lvconvert)) {
log_error("Repair of mirrored device %s failed.", device);
return 0;
}
r = dmeventd_lvm2_run_with_lock(cmd_lvconvert);
log_info("Repair of mirrored device %s finished successfully.", device);
log_info("Repair of mirrored device %s.",
(r) ? "finished successfully" : "failed");
return 1;
return r;
}
void process_event(struct dm_task *dmt,
@@ -152,8 +154,7 @@ void process_event(struct dm_task *dmt,
case ME_FAILURE:
log_error("Device failure in %s.", device);
if (!_remove_failed_devices(state->cmd_lvscan,
state->cmd_lvconvert,
device))
state->cmd_lvconvert))
/* FIXME Why are all the error return codes unused? Get rid of them? */
log_error("Failed to remove faulty devices in %s.",
device);
@@ -167,7 +168,7 @@ void process_event(struct dm_task *dmt,
break;
default:
/* FIXME Provide value then! */
log_warn("WARNING: %s received unknown event.", device);
log_info("Unknown event received.");
}
} while (next);
}

View File

@@ -76,7 +76,7 @@ static int _process_raid_event(struct dso_state *state, char *params, const char
/* if repair goes OK, report success even if lvscan has failed */
if (!dmeventd_lvm2_run_with_lock(state->cmd_lvconvert)) {
log_error("Repair of RAID device %s failed.", device);
log_info("Repair of RAID device %s failed.", device);
r = 0;
}
} else {

View File

@@ -301,7 +301,7 @@ out:
static int _use_policy(struct dm_task *dmt, struct dso_state *state)
{
#if THIN_DEBUG
log_debug("dmeventd executes: %s.", state->cmd_str);
log_info("dmeventd executes: %s.", state->cmd_str);
#endif
if (!dmeventd_lvm2_run_with_lock(state->cmd_str)) {
log_error("Failed to extend thin pool %s.",

View File

@@ -7,13 +7,19 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import threading
import subprocess
from . import cfg
import time
from .cmdhandler import options_to_cli_args
import dbus
from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug
import traceback
import os
_rlock = threading.RLock()
_thread_list = list()
def pv_move_lv_cmd(move_options, lv_full_name,
pv_source, pv_source_range, pv_dest_range_list):
@@ -36,40 +42,15 @@ def lv_merge_cmd(merge_options, lv_full_name):
return cmd
def _move_merge(interface_name, command, job_state):
# We need to execute these command stand alone by forking & exec'ing
# the command always as we will be getting periodic output from them on
# the status of the long running operation.
command.insert(0, cfg.LVM_CMD)
process = subprocess.Popen(command, stdout=subprocess.PIPE,
env=os.environ,
stderr=subprocess.PIPE, close_fds=True)
def _move_merge(interface_name, cmd, job_state):
add(cmd, job_state)
log_debug("Background process for %s is %d" %
(str(command), process.pid))
lines_iterator = iter(process.stdout.readline, b"")
for line in lines_iterator:
line_str = line.decode("utf-8")
# Check to see if the line has the correct number of separators
try:
if line_str.count(':') == 2:
(device, ignore, percentage) = line_str.split(':')
job_state.Percent = round(
float(percentage.strip()[:-1]), 1)
except ValueError:
log_error("Trying to parse percentage which failed for %s" %
line_str)
out = process.communicate()
if process.returncode == 0:
job_state.Percent = 100
else:
done = job_state.Wait(-1)
if not done:
ec, err_msg = job_state.GetError
raise dbus.exceptions.DBusException(
interface_name,
'Exit code %s, stderr = %s' % (str(process.returncode), out[1]))
'Exit code %s, stderr = %s' % (str(ec), err_msg))
cfg.load()
return '/'
@@ -104,6 +85,8 @@ def move(interface_name, lv_name, pv_src_obj, pv_source_range,
pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
# Generate the command line for this command, but don't
# execute it.
cmd = pv_move_lv_cmd(move_options,
lv_name,
pv_src.lvm_id,
@@ -126,3 +109,106 @@ def merge(interface_name, lv_uuid, lv_name, merge_options, job_state):
raise dbus.exceptions.DBusException(
interface_name,
'LV with uuid %s and name %s not present!' % (lv_uuid, lv_name))
def background_reaper():
while cfg.run.value != 0:
with _rlock:
num_threads = len(_thread_list) - 1
if num_threads >= 0:
for i in range(num_threads, -1, -1):
_thread_list[i].join(0)
if not _thread_list[i].is_alive():
log_debug("Removing thread: %s" % _thread_list[i].name)
_thread_list.pop(i)
time.sleep(3)
def background_execute(command, background_job):
# Wrap this whole operation in an exception handler, otherwise if we
# hit a code bug we will silently exit this thread without anyone being
# the wiser.
try:
# We need to execute these command stand alone by forking & exec'ing
# the command always!
command.insert(0, cfg.LVM_CMD)
process = subprocess.Popen(command, stdout=subprocess.PIPE,
env=os.environ,
stderr=subprocess.PIPE, close_fds=True)
log_debug("Background process for %s is %d" %
(str(command), process.pid))
lines_iterator = iter(process.stdout.readline, b"")
for line in lines_iterator:
line_str = line.decode("utf-8")
# Check to see if the line has the correct number of separators
try:
if line_str.count(':') == 2:
(device, ignore, percentage) = line_str.split(':')
background_job.Percent = round(
float(percentage.strip()[:-1]), 1)
except ValueError:
log_error("Trying to parse percentage which failed for %s" %
line_str)
out = process.communicate()
if process.returncode == 0:
background_job.Percent = 100
else:
log_error("Failed to execute background job %s, STDERR= %s"
% (str(command), out[1]))
background_job.set_result(process.returncode, out[1])
log_debug("Background process %d complete!" % process.pid)
except Exception:
# In the unlikely event that we blow up, we need to unblock caller which
# is waiting on an answer.
st = traceback.format_exc()
error = "Exception in background thread: \n%s" % st
log_error(error)
background_job.set_result(1, error)
def add(command, reporting_job):
# Create the thread, get it running and then add it to the list
t = threading.Thread(
target=background_execute,
name="thread: " + ' '.join(command),
args=(command, reporting_job))
t.start()
with _rlock:
_thread_list.append(t)
def wait_thread(job, timeout, cb, cbe):
# We need to put the wait on it's own thread, so that we don't block the
# entire dbus queue processing thread
try:
cb(job.state.Wait(timeout))
except Exception as e:
cbe("Wait exception: %s" % str(e))
return 0
def add_wait(job, timeout, cb, cbe):
if timeout == 0:
# Users are basically polling, do not create thread
cb(job.Complete)
else:
t = threading.Thread(
target=wait_thread,
name="thread job.Wait: %s" % job.dbus_object_path(),
args=(job, timeout, cb, cbe)
)
t.start()
with _rlock:
_thread_list.append(t)

View File

@@ -11,37 +11,20 @@ from .pv import load_pvs
from .vg import load_vgs
from .lv import load_lvs
from . import cfg
from .utils import MThreadRunner, log_debug
def _main_thread_load(refresh=True, emit_signal=True):
def load(refresh=True, emit_signal=True, cache_refresh=True, log=True):
num_total_changes = 0
num_total_changes += load_pvs(
refresh=refresh,
emit_signal=emit_signal,
cache_refresh=False)[1]
num_total_changes += load_vgs(
refresh=refresh,
emit_signal=emit_signal,
cache_refresh=False)[1]
num_total_changes += load_lvs(
refresh=refresh,
emit_signal=emit_signal,
cache_refresh=False)[1]
return num_total_changes
def load(refresh=True, emit_signal=True, cache_refresh=True, log=True,
need_main_thread=True):
# Go through and load all the PVs, VGs and LVs
if cache_refresh:
cfg.db.refresh(log)
if need_main_thread:
rc = MThreadRunner(_main_thread_load, refresh, emit_signal).done()
else:
rc = _main_thread_load(refresh, emit_signal)
num_total_changes += load_pvs(refresh=refresh, emit_signal=emit_signal,
cache_refresh=False)[1]
num_total_changes += load_vgs(refresh=refresh, emit_signal=emit_signal,
cache_refresh=False)[1]
num_total_changes += load_lvs(refresh=refresh, emit_signal=emit_signal,
cache_refresh=False)[1]
return rc
return num_total_changes

View File

@@ -8,54 +8,12 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from .automatedproperties import AutomatedProperties
from .utils import job_obj_path_generate, mt_async_result, log_debug
from .utils import job_obj_path_generate
from . import cfg
from .cfg import JOB_INTERFACE
import dbus
import threading
from gi.repository import GLib
# Class that handles a client waiting for something to be complete. We either
# get a timeout or the operation is done.
class WaitingClient(object):
# A timeout occurred
@staticmethod
def _timeout(wc):
with wc.rlock:
if wc.in_use:
wc.in_use = False
# Remove ourselves from waiting client
wc.job_state.remove_waiting_client(wc)
wc.timer_id = -1
mt_async_result(wc.cb, wc.job_state.Complete)
wc.job_state = None
def __init__(self, job_state, tmo, cb, cbe):
self.rlock = threading.RLock()
self.job_state = job_state
self.cb = cb
self.cbe = cbe
self.in_use = True # Indicates if object is in play
self.timer_id = -1
if tmo > 0:
self.timer_id = GLib.timeout_add_seconds(
tmo, WaitingClient._timeout, self)
# The job finished before the timer popped and we are being notified that
# it's done
def notify(self):
with self.rlock:
if self.in_use:
self.in_use = False
# Clear timer
if self.timer_id != -1:
GLib.source_remove(self.timer_id)
self.timer_id = -1
mt_async_result(self.cb, self.job_state.Complete)
self.job_state = None
from . import background
# noinspection PyPep8Naming
@@ -66,9 +24,9 @@ class JobState(object):
self._percent = 0
self._complete = False
self._request = request
self._cond = threading.Condition(self.rlock)
self._ec = 0
self._stderr = ''
self._waiting_clients = []
# This is an lvm command that is just taking too long and doesn't
# support background operation
@@ -99,7 +57,7 @@ class JobState(object):
with self.rlock:
self._complete = value
self._percent = 100
self.notify_waiting_clients()
self._cond.notify_all()
@property
def GetError(self):
@@ -113,10 +71,29 @@ class JobState(object):
else:
return (-1, 'Job is not complete!')
def set_result(self, ec, msg):
with self.rlock:
self.Complete = True
self._ec = ec
self._stderr = msg
def dtor(self):
with self.rlock:
self._request = None
def Wait(self, timeout):
try:
with self._cond:
# Check to see if we are done, before we wait
if not self.Complete:
if timeout != -1:
self._cond.wait(timeout)
else:
self._cond.wait()
return self.Complete
except RuntimeError:
return False
@property
def Result(self):
with self.rlock:
@@ -124,36 +101,6 @@ class JobState(object):
return self._request.result()
return '/'
def add_waiting_client(self, client):
with self.rlock:
# Avoid race condition where it goes complete before we get added
# to the list of waiting clients
if self.Complete:
client.notify()
else:
self._waiting_clients.append(client)
def remove_waiting_client(self, client):
# If a waiting client timer pops before the job is done we will allow
# the client to remove themselves from the list. As we have a lock
# here and a lock in the waiting client too, and they can be obtained
# in different orders, a dead lock can occur.
# As this remove is really optional, we will try to acquire the lock
# and remove. If we are unsuccessful it's not fatal, we just delay
# the time when the objects can be garbage collected by python
if self.rlock.acquire(False):
try:
self._waiting_clients.remove(client)
finally:
self.rlock.release()
def notify_waiting_clients(self):
with self.rlock:
for c in self._waiting_clients:
c.notify()
self._waiting_clients = []
# noinspection PyPep8Naming
class Job(AutomatedProperties):
@@ -175,6 +122,10 @@ class Job(AutomatedProperties):
def Percent(self):
return dbus.Double(float(self.state.Percent))
@Percent.setter
def Percent(self, value):
self.state.Percent = value
@property
def Complete(self):
return dbus.Boolean(self.state.Complete)
@@ -187,6 +138,9 @@ class Job(AutomatedProperties):
def GetError(self):
return dbus.Struct(self.state.GetError, signature="(is)")
def set_result(self, ec, msg):
self.state.set_result(ec, msg)
@dbus.service.method(dbus_interface=JOB_INTERFACE)
def Remove(self):
if self.state.Complete:
@@ -201,11 +155,7 @@ class Job(AutomatedProperties):
out_signature='b',
async_callbacks=('cb', 'cbe'))
def Wait(self, timeout, cb, cbe):
if timeout == 0 or self.state.Complete:
cb(dbus.Boolean(self.state.Complete))
else:
self.state.add_waiting_client(
WaitingClient(self.state, timeout, cb, cbe))
background.add_wait(self, timeout, cb, cbe)
@property
def Result(self):

View File

@@ -21,7 +21,7 @@ from .utils import n, n32
from .loader import common
from .state import State
from . import background
from .utils import round_size, mt_remove_dbus_objects
from .utils import round_size
from .job import JobState
@@ -415,6 +415,7 @@ class Lv(LvCommon):
rc, out, err = cmdhandler.lv_remove(lv_name, remove_options)
if rc == 0:
cfg.om.remove_object(dbo, True)
cfg.load()
else:
# Need to work on error handling, need consistent
@@ -514,9 +515,15 @@ class Lv(LvCommon):
rc, out, err = cmdhandler.vg_lv_snapshot(
lv_name, snapshot_options, name, optional_size)
if rc == 0:
cfg.load()
return_path = '/'
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
return cfg.om.get_object_path_by_lvm_id(full_name)
lvs = load_lvs([full_name], emit_signal=True)[0]
for l in lvs:
return_path = l.dbus_object_path()
# Refresh self and all included PVs
cfg.load(cache_refresh=False)
return return_path
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
@@ -745,8 +752,9 @@ class LvThinPool(Lv):
lv_name, create_options, name, size_bytes)
if rc == 0:
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
cfg.load()
lv_created = cfg.om.get_object_path_by_lvm_id(full_name)
lvs = load_lvs([full_name], emit_signal=True)[0]
for l in lvs:
lv_created = l.dbus_object_path()
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
@@ -808,7 +816,8 @@ class LvCachePool(Lv):
# When we cache an LV, the cache pool and the lv that is getting
# cached need to be removed from the object manager and
# re-created as their interfaces have changed!
mt_remove_dbus_objects((dbo, lv_to_cache))
cfg.om.remove_object(dbo, emit_signal=True)
cfg.om.remove_object(lv_to_cache, emit_signal=True)
cfg.load()
lv_converted = cfg.om.get_object_path_by_lvm_id(fcn)
@@ -870,7 +879,8 @@ class LvCacheLv(Lv):
if rc == 0:
# The cache pool gets removed as hidden and put back to
# visible, so lets delete
mt_remove_dbus_objects((cache_pool, dbo))
cfg.om.remove_object(cache_pool, emit_signal=True)
cfg.om.remove_object(dbo, emit_signal=True)
cfg.load()
uncached_lv_path = cfg.om.get_object_path_by_lvm_id(lv_name)

View File

@@ -22,6 +22,7 @@ from . import lvmdb
from gi.repository import GLib
from .fetch import load
from .manager import Manager
from .background import background_reaper
import traceback
import queue
from . import udevwatch
@@ -63,7 +64,6 @@ def _discard_pending_refreshes():
def process_request():
while cfg.run.value != 0:
# noinspection PyBroadException
try:
req = cfg.worker_q.get(True, 5)
@@ -85,7 +85,7 @@ def process_request():
log_debug(
"Inspect method %s for too many refreshes" %
(str(req.method)))
log_debug("Method complete ")
log_debug("Complete ")
except queue.Empty:
pass
except Exception:
@@ -156,11 +156,14 @@ def main():
cfg.db = lvmdb.DataStore(cfg.args.use_json)
# Using a thread to process requests, we cannot hang the dbus library
# thread that is handling the dbus interface
# Start up thread to monitor pv moves
thread_list.append(
threading.Thread(target=background_reaper, name="pv_move_reaper"))
# Using a thread to process requests.
thread_list.append(threading.Thread(target=process_request))
cfg.load(refresh=False, emit_signal=False, need_main_thread=False)
cfg.load(refresh=False, emit_signal=False)
cfg.loop = GLib.MainLoop()
for process in thread_list:

View File

@@ -42,10 +42,12 @@ class Manager(AutomatedProperties):
raise dbus.exceptions.DBusException(
MANAGER_INTERFACE, "PV Already exists!")
created_pv = []
rc, out, err = cmdhandler.pv_create(create_options, [device])
if rc == 0:
cfg.load()
created_pv = cfg.om.get_object_path_by_lvm_id(device)
pvs = load_pvs([device], emit_signal=True)[0]
for p in pvs:
created_pv = p.dbus_object_path()
else:
raise dbus.exceptions.DBusException(
MANAGER_INTERFACE,
@@ -78,14 +80,20 @@ class Manager(AutomatedProperties):
MANAGER_INTERFACE, 'object path = %s not found' % p)
rc, out, err = cmdhandler.vg_create(create_options, pv_devices, name)
created_vg = "/"
if rc == 0:
cfg.load()
return cfg.om.get_object_path_by_lvm_id(name)
vgs = load_vgs([name], emit_signal=True)[0]
for v in vgs:
created_vg = v.dbus_object_path()
# Update the PVS
load_pvs(refresh=True, emit_signal=True, cache_refresh=False)
else:
raise dbus.exceptions.DBusException(
MANAGER_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
return created_vg
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,

View File

@@ -18,7 +18,7 @@ from .utils import vg_obj_path_generate, n, pv_obj_path_generate, \
from .loader import common
from .request import RequestEntry
from .state import State
from .utils import round_size, mt_remove_dbus_objects
from .utils import round_size
# noinspection PyUnusedLocal
@@ -140,7 +140,7 @@ class Pv(AutomatedProperties):
if dbo:
rc, out, err = cmdhandler.pv_remove(pv_name, remove_options)
if rc == 0:
mt_remove_dbus_objects((dbo,))
cfg.om.remove_object(dbo, True)
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
@@ -174,7 +174,7 @@ class Pv(AutomatedProperties):
rc, out, err = cmdhandler.pv_resize(pv_name, new_size_bytes,
resize_options)
if rc == 0:
cfg.load()
dbo.refresh()
else:
raise dbus.exceptions.DBusException(
PV_INTERFACE,

View File

@@ -13,7 +13,7 @@ from gi.repository import GLib
from .job import Job
from . import cfg
import traceback
from .utils import log_error, mt_async_result
from .utils import log_error
class RequestEntry(object):
@@ -57,9 +57,9 @@ class RequestEntry(object):
self._job = Job(self, self._job_state)
cfg.om.register_object(self._job, True)
if self._return_tuple:
mt_async_result(self.cb, ('/', self._job.dbus_object_path()))
self.cb(('/', self._job.dbus_object_path()))
else:
mt_async_result(self.cb, self._job.dbus_object_path())
self.cb(self._job.dbus_object_path())
def run_cmd(self):
try:
@@ -110,9 +110,9 @@ class RequestEntry(object):
if error_rc == 0:
if self.cb:
if self._return_tuple:
mt_async_result(self.cb, (result, '/'))
self.cb((result, '/'))
else:
mt_async_result(self.cb, result)
self.cb(result)
else:
if self.cb_error:
if not error_exception:
@@ -123,7 +123,7 @@ class RequestEntry(object):
else:
error_exception = Exception(error_msg)
mt_async_result(self.cb_error, error_exception)
self.cb_error(error_exception)
else:
# We have a job and it's complete, indicate that it's done.
# TODO: We need to signal the job is done too.

View File

@@ -17,8 +17,6 @@ import datetime
import dbus
from lvmdbusd import cfg
from gi.repository import GLib
import threading
STDOUT_TTY = os.isatty(sys.stdout.fileno())
@@ -496,64 +494,3 @@ def validate_tag(interface, tag):
raise dbus.exceptions.DBusException(
interface, 'tag (%s) contains invalid character, allowable set(%s)'
% (tag, _ALLOWABLE_TAG_CH))
# The methods below which start with mt_* are used to execute the desired code
# on the the main thread of execution to alleviate any issues the dbus-python
# library with regards to multi-threaded access. Essentially, we are trying to
# ensure all dbus library interaction is done from the same thread!
def _async_result(call_back, results):
log_debug('Results = %s' % str(results))
call_back(results)
# Return result in main thread
def mt_async_result(call_back, results):
GLib.idle_add(_async_result, call_back, results)
# Run the supplied function and arguments on the main thread and wait for them
# to complete while allowing the ability to get the return value too.
#
# Example:
# result = MThreadRunner(foo, arg1, arg2).done()
#
class MThreadRunner(object):
@staticmethod
def runner(obj):
obj._run()
with obj.cond:
obj.function_complete = True
obj.cond.notify_all()
def __init__(self, function, *args):
self.f = function
self.rc = None
self.args = args
self.function_complete = False
self.cond = threading.Condition(threading.Lock())
def done(self):
GLib.idle_add(MThreadRunner.runner, self)
with self.cond:
if not self.function_complete:
self.cond.wait()
return self.rc
def _run(self):
if len(self.args):
self.rc = self.f(*self.args)
else:
self.rc = self.f()
def _remove_objects(dbus_objects_rm):
for o in dbus_objects_rm:
cfg.om.remove_object(o, emit_signal=True)
# Remove dbus objects from main thread
def mt_remove_dbus_objects(objs):
MThreadRunner(_remove_objects, objs).done()

View File

@@ -19,7 +19,7 @@ from .request import RequestEntry
from .loader import common
from .state import State
from . import background
from .utils import round_size, mt_remove_dbus_objects
from .utils import round_size
from .job import JobState
@@ -191,7 +191,14 @@ class Vg(AutomatedProperties):
rc, out, err = cmdhandler.vg_remove(vg_name, remove_options)
if rc == 0:
# Remove the VG
cfg.om.remove_object(dbo, True)
# If an LV has hidden LVs, things can get quite involved,
# especially if it's the last thin pool to get removed, so
# lets refresh all
cfg.load()
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
@@ -598,7 +605,9 @@ class Vg(AutomatedProperties):
rc, out, err = create_method(
md.lv_full_name(), data.lv_full_name(), create_options)
if rc == 0:
mt_remove_dbus_objects((md, data))
cfg.om.remove_object(md, emit_signal=True)
cfg.om.remove_object(data, emit_signal=True)
cache_pool_lv = Vg.fetch_new_lv(vg_name, new_name)
else:
raise dbus.exceptions.DBusException(

View File

@@ -370,11 +370,6 @@ void activation_exit(void)
{
}
int raid4_is_supported(struct cmd_context *cmd, const struct segment_type *segtype)
{
return 1;
}
int lv_is_active(const struct logical_volume *lv)
{
return 0;
@@ -1494,26 +1489,6 @@ out:
return r || l;
}
/*
* Check if "raid4" @segtype is supported by kernel.
*
* if segment type is not raid4, return 1.
*/
int raid4_is_supported(struct cmd_context *cmd, const struct segment_type *segtype)
{
unsigned attrs;
if (segtype_is_raid4(segtype) &&
(!segtype->ops->target_present ||
!segtype->ops->target_present(cmd, NULL, &attrs) ||
!(attrs & RAID_FEATURE_RAID4))) {
log_error("RAID module does not support RAID4.");
return 0;
}
return 1;
}
int lv_is_active(const struct logical_volume *lv)
{
return _lv_is_active(lv, NULL, NULL, NULL);
@@ -1708,7 +1683,7 @@ int target_register_events(struct cmd_context *cmd, const char *dso, const struc
if (!r)
return_0;
log_very_verbose("%s %s for events", set ? "Monitored" : "Unmonitored", uuid);
log_info("%s %s for events", set ? "Monitored" : "Unmonitored", uuid);
return 1;
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -99,7 +99,6 @@ int target_present(struct cmd_context *cmd, const char *target_name,
int use_modprobe);
int target_version(const char *target_name, uint32_t *maj,
uint32_t *min, uint32_t *patchlevel);
int raid4_is_supported(struct cmd_context *cmd, const struct segment_type *segtype);
int lvm_dm_prefix_check(int major, int minor, const char *prefix);
int list_segment_modules(struct dm_pool *mem, const struct lv_segment *seg,
struct dm_list *modules);

View File

@@ -2250,8 +2250,8 @@ bad:
return NULL;
}
static char *_add_error_or_zero_device(struct dev_manager *dm, struct dm_tree *dtree,
struct lv_segment *seg, int s, int use_zero)
static char *_add_error_device(struct dev_manager *dm, struct dm_tree *dtree,
struct lv_segment *seg, int s)
{
char *dlid, *name;
char errid[32];
@@ -2262,15 +2262,13 @@ static char *_add_error_or_zero_device(struct dev_manager *dm, struct dm_tree *d
uint64_t size = (uint64_t) seg->len * seg->lv->vg->extent_size;
dm_list_iterate_items(seg_i, &seg->lv->segments) {
if (seg == seg_i) {
if (seg == seg_i)
segno = i;
break;
}
++i;
}
if (segno < 0) {
log_error(INTERNAL_ERROR "_add_error_or_zero_device called with bad segment.");
log_error("_add_error_device called with bad segment");
return NULL;
}
@@ -2283,7 +2281,7 @@ static char *_add_error_or_zero_device(struct dev_manager *dm, struct dm_tree *d
seg->lv->name, errid)))
return_NULL;
log_debug_activation("Getting device info for %s [%s].", name, dlid);
log_debug_activation("Getting device info for %s [%s]", name, dlid);
if (!_info(dm->cmd, dlid, 1, 0, &info, NULL, NULL)) {
log_error("Failed to get info for %s [%s].", name, dlid);
return 0;
@@ -2293,19 +2291,14 @@ static char *_add_error_or_zero_device(struct dev_manager *dm, struct dm_tree *d
/* Create new node */
if (!(node = dm_tree_add_new_dev(dtree, name, dlid, 0, 0, 0, 0, 0)))
return_NULL;
if (use_zero) {
if (!dm_tree_node_add_zero_target(node, size))
return_NULL;
} else
if (!dm_tree_node_add_error_target(node, size))
return_NULL;
if (!dm_tree_node_add_error_target(node, size))
return_NULL;
} else {
/* Already exists */
if (!dm_tree_add_dev(dtree, info.major, info.minor)) {
log_error("Failed to add device (%" PRIu32 ":%" PRIu32") to dtree.",
log_error("Failed to add device (%" PRIu32 ":%" PRIu32") to dtree",
info.major, info.minor);
return NULL;
return_NULL;
}
}
@@ -2317,15 +2310,14 @@ static int _add_error_area(struct dev_manager *dm, struct dm_tree_node *node,
{
char *dlid;
uint64_t extent_size = seg->lv->vg->extent_size;
int use_zero = !strcmp(dm->cmd->stripe_filler, TARGET_NAME_ZERO) ? 1 : 0;
if (!strcmp(dm->cmd->stripe_filler, TARGET_NAME_ERROR) || use_zero) {
if (!strcmp(dm->cmd->stripe_filler, TARGET_NAME_ERROR)) {
/*
* FIXME, the tree pointer is first field of dm_tree_node, but
* we don't have the struct definition available.
*/
struct dm_tree **tree = (struct dm_tree **) node;
if (!(dlid = _add_error_or_zero_device(dm, *tree, seg, s, use_zero)))
if (!(dlid = _add_error_device(dm, *tree, seg, s)))
return_0;
if (!dm_tree_node_add_target_area(node, NULL, dlid, extent_size * seg_le(seg, s)))
return_0;
@@ -2833,7 +2825,7 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, lv->name, layer)))
return_0;
/* Even unused thin-pool still needs to get layered UUID -suffix */
/* Even unused thin-pool still needs to get layered UUID -suffix */
if (!layer && lv_is_new_thin_pool(lv))
layer = lv_layer(lv);

View File

@@ -640,8 +640,8 @@ static int _process_config(struct cmd_context *cmd)
if (!strcmp(cmd->stripe_filler, "/dev/ioerror") &&
stat(cmd->stripe_filler, &st))
cmd->stripe_filler = "error";
else if (strcmp(cmd->stripe_filler, "error") &&
strcmp(cmd->stripe_filler, "zero")) {
if (strcmp(cmd->stripe_filler, "error")) {
if (stat(cmd->stripe_filler, &st)) {
log_warn("WARNING: activation/missing_stripe_filler = \"%s\" "
"is invalid,", cmd->stripe_filler);

View File

@@ -94,13 +94,6 @@ struct cmd_context {
struct arg_values *opt_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.
*/

View File

@@ -1111,8 +1111,7 @@ cfg(activation_retry_deactivation_CFG, "retry_deactivation", activation_CFG_SECT
cfg(activation_missing_stripe_filler_CFG, "missing_stripe_filler", activation_CFG_SECTION, CFG_ADVANCED, CFG_TYPE_STRING, DEFAULT_STRIPE_FILLER, vsn(1, 0, 0), NULL, 0, NULL,
"Method to fill missing stripes when activating an incomplete LV.\n"
"Using 'error' will make inaccessible parts of the device return I/O\n"
"errors on access. Using 'zero' will return success (and zero) on I/O\n"
"You can instead use a device path, in which case,\n"
"errors on access. You can instead use a device path, in which case,\n"
"that device will be used in place of missing stripes. Using anything\n"
"other than 'error' with mirrored or snapshotted volumes is likely to\n"
"result in data corruption.\n")

View File

@@ -40,7 +40,7 @@ static int _extract_pattern(struct dm_pool *mem, const char *pat,
break;
default:
log_error("Pattern must begin with 'a' or 'r'.");
log_info("pattern must begin with 'a' or 'r'");
return 0;
}
pat++;
@@ -77,7 +77,7 @@ static int _extract_pattern(struct dm_pool *mem, const char *pat,
*/
ptr = r + strlen(r) - 1;
if (*ptr != sep) {
log_error("Invalid separator at end of regex.");
log_info("invalid separator at end of regex");
return 0;
}
*ptr = '\0';

View File

@@ -168,7 +168,7 @@ static int _parse_dev(const char *file, FILE *fp, dev_t *result)
}
if (sscanf(buffer, "%u:%u", &major, &minor) != 2) {
log_error("Incorrect format for sysfs device file: %s.", file);
log_info("sysfs device file not correct format");
return 0;
}

View File

@@ -140,18 +140,18 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
sector + scan_sector);
}
if (xlate64(lh->sector_xl) != sector + scan_sector) {
log_very_verbose("%s: Label for sector %" PRIu64
" found at sector %" PRIu64
" - ignoring", dev_name(dev),
(uint64_t)xlate64(lh->sector_xl),
sector + scan_sector);
log_info("%s: Label for sector %" PRIu64
" found at sector %" PRIu64
" - ignoring", dev_name(dev),
(uint64_t)xlate64(lh->sector_xl),
sector + scan_sector);
continue;
}
if (calc_crc(INITIAL_CRC, (uint8_t *)&lh->offset_xl, LABEL_SIZE -
((uint8_t *) &lh->offset_xl - (uint8_t *) lh)) !=
xlate32(lh->crc_xl)) {
log_very_verbose("Label checksum incorrect on %s - "
"ignoring", dev_name(dev));
log_info("Label checksum incorrect on %s - "
"ignoring", dev_name(dev));
continue;
}
if (found)
@@ -243,8 +243,8 @@ int label_remove(struct device *dev)
}
if (wipe) {
log_very_verbose("%s: Wiping label at sector %" PRIu64,
dev_name(dev), sector);
log_info("%s: Wiping label at sector %" PRIu64,
dev_name(dev), sector);
if (!dev_write(dev, sector << SECTOR_SHIFT, LABEL_SIZE,
buf)) {
log_error("Failed to remove label from %s at "
@@ -333,9 +333,9 @@ int label_write(struct device *dev, struct label *label)
if (!dev_open(dev))
return_0;
log_very_verbose("%s: Writing label to sector %" PRIu64 " with stored offset %"
PRIu32 ".", dev_name(dev), label->sector,
xlate32(lh->offset_xl));
log_info("%s: Writing label to sector %" PRIu64 " with stored offset %"
PRIu32 ".", dev_name(dev), label->sector,
xlate32(lh->offset_xl));
if (!dev_write(dev, label->sector << SECTOR_SHIFT, LABEL_SIZE, buf)) {
log_debug_devs("Failed to write label to %s", dev_name(dev));
r = 0;

View File

@@ -67,7 +67,7 @@ struct log_stream_item {
char *buffer;
};
static struct log_stream {
struct log_stream {
struct log_stream_item out;
struct log_stream_item err;
struct log_stream_item report;
@@ -476,9 +476,9 @@ static void _vprint_log(int level, const char *file, int line, int dm_errno_or_c
int bufused, n;
const char *trformat; /* Translated format string */
char *newbuf;
int use_stderr = log_stderr(level);
int log_once = log_once(level);
int log_bypass_report = log_bypass_report(level);
int use_stderr = level & _LOG_STDERR;
int log_once = level & _LOG_ONCE;
int log_bypass_report = level & _LOG_BYPASS_REPORT;
int fatal_internal_error = 0;
size_t msglen;
const char *indent_spaces = "";
@@ -489,7 +489,7 @@ static void _vprint_log(int level, const char *file, int line, int dm_errno_or_c
struct dm_report *orig_report;
int logged_via_report = 0;
level = log_level(level);
level &= ~(_LOG_STDERR|_LOG_ONCE|_LOG_BYPASS_REPORT);
if (_abort_on_internal_errors_env_present < 0) {
if ((env_str = getenv("DM_ABORT_ON_INTERNAL_ERRORS"))) {
@@ -715,8 +715,8 @@ void print_log_libdm(int level, const char *file, int line, int dm_errno_or_clas
* LOG_WARN level and it's not going to stderr (so we're
* printing common message that is not an error/warning).
*/
if (!log_stderr(level) &&
(log_level(level) == _LOG_WARN))
if (!(level & _LOG_STDERR) &&
((level & ~(_LOG_STDERR|_LOG_ONCE|_LOG_BYPASS_REPORT)) == _LOG_WARN))
level |= _LOG_BYPASS_REPORT;
_log_stream.out.stream = report_stream;

View File

@@ -50,10 +50,6 @@
#define _LOG_STDERR 0x0080 /* force things to go to stderr, even if loglevel would make them go to stdout */
#define _LOG_ONCE 0x0100 /* downgrade to NOTICE if this has been already logged */
#define _LOG_BYPASS_REPORT 0x0200 /* do not log through report even if report available */
#define log_level(x) ((x) & 0x0f) /* obtain message level */
#define log_stderr(x) ((x) & _LOG_STDERR) /* obtain stderr bit */
#define log_once(x) ((x) & _LOG_ONCE) /* obtain once bit */
#define log_bypass_report(x) ((x) & _LOG_BYPASS_REPORT)/* obtain bypass bit */
#define INTERNAL_ERROR "Internal error: "

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -1418,7 +1418,6 @@ int lv_active_change(struct cmd_context *cmd, struct logical_volume *lv,
enum activation_change activate, int needs_exclusive)
{
const char *ay_with_mode = NULL;
struct lv_segment *seg = first_seg(lv);
if (activate == CHANGE_ASY)
ay_with_mode = "sh";
@@ -1455,9 +1454,6 @@ deactivate:
break;
case CHANGE_ALY:
case CHANGE_AAY:
if (!raid4_is_supported(cmd, seg->segtype))
goto no_raid4;
if (needs_exclusive || _lv_is_exclusive(lv)) {
log_verbose("Activating logical volume %s exclusively locally.",
display_lvname(lv));
@@ -1472,9 +1468,6 @@ deactivate:
break;
case CHANGE_AEY:
exclusive:
if (!raid4_is_supported(cmd, seg->segtype))
goto no_raid4;
log_verbose("Activating logical volume %s exclusively.",
display_lvname(lv));
if (!activate_lv_excl(cmd, lv))
@@ -1483,9 +1476,6 @@ exclusive:
case CHANGE_ASY:
case CHANGE_AY:
default:
if (!raid4_is_supported(cmd, seg->segtype))
goto no_raid4;
if (needs_exclusive || _lv_is_exclusive(lv))
goto exclusive;
log_verbose("Activating logical volume %s.", display_lvname(lv));
@@ -1498,10 +1488,6 @@ exclusive:
log_error("Failed to unlock logical volume %s.", display_lvname(lv));
return 1;
no_raid4:
log_error("Failed to activate %s LV %s", lvseg_name(seg), display_lvname(lv));
return 0;
}
char *lv_active_dup(struct dm_pool *mem, const struct logical_volume *lv)

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;
@@ -3843,7 +3844,6 @@ static int _lv_extend_layered_lv(struct alloc_handle *ah,
uint32_t fa, s;
int clear_metadata = 0;
uint32_t area_multiple = 1;
int fail;
if (!(segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_STRIPED)))
return_0;
@@ -3917,60 +3917,45 @@ static int _lv_extend_layered_lv(struct alloc_handle *ah,
if (!vg_write(lv->vg) || !vg_commit(lv->vg))
return_0;
if (test_mode())
log_verbose("Test mode: Skipping wiping of metadata areas.");
else {
fail = 0;
/* Activate all rmeta devices locally first (more efficient) */
for (s = 0; !fail && s < seg->area_count; s++) {
meta_lv = seg_metalv(seg, s);
for (s = 0; s < seg->area_count; s++) {
meta_lv = seg_metalv(seg, s);
if (!activate_lv_local(meta_lv->vg->cmd, meta_lv)) {
log_error("Failed to activate %s for clearing.",
display_lvname(meta_lv));
fail = 1;
}
if (test_mode()) {
lv_set_hidden(meta_lv);
continue;
}
/* Clear all rmeta devices */
for (s = 0; !fail && s < seg->area_count; s++) {
meta_lv = seg_metalv(seg, s);
log_verbose("Clearing metadata area of %s.",
display_lvname(meta_lv));
/*
* Rather than wiping meta_lv->size, we can simply
* wipe '1' to remove the superblock of any previous
* RAID devices. It is much quicker.
*/
if (!wipe_lv(meta_lv, (struct wipe_params)
{ .do_zero = 1, .zero_sectors = 1 })) {
stack;
fail = 1;
}
/* For clearing, simply activate locally */
if (!activate_lv_local(meta_lv->vg->cmd, meta_lv)) {
log_error("Failed to activate %s/%s for clearing",
meta_lv->vg->name, meta_lv->name);
return 0;
}
/* Deactivate all rmeta devices */
for (s = 0; s < seg->area_count; s++) {
meta_lv = seg_metalv(seg, s);
if (!deactivate_lv(meta_lv->vg->cmd, meta_lv)) {
log_error("Failed to deactivate %s after clearing.",
display_lvname(meta_lv));
fail = 1;
}
/* Wipe any temporary tags required for activation. */
str_list_wipe(&meta_lv->tags);
log_verbose("Clearing metadata area of %s",
display_lvname(meta_lv));
/*
* Rather than wiping meta_lv->size, we can simply
* wipe '1' to remove the superblock of any previous
* RAID devices. It is much quicker.
*/
if (!wipe_lv(meta_lv, (struct wipe_params)
{ .do_zero = 1, .zero_sectors = 1 })) {
log_error("Failed to zero %s/%s",
meta_lv->vg->name, meta_lv->name);
return 0;
}
if (fail)
/* Fail, after trying to deactivate all we could */
return_0;
if (!deactivate_lv(meta_lv->vg->cmd, meta_lv)) {
log_error("Failed to deactivate %s/%s",
meta_lv->vg->name, meta_lv->name);
return 0;
}
lv_set_hidden(meta_lv);
/* Wipe any temporary tags required for activation. */
str_list_wipe(&meta_lv->tags);
}
for (s = 0; s < seg->area_count; s++)
lv_set_hidden(seg_metalv(seg, s));
}
seg->area_len += extents / area_multiple;

View File

@@ -1066,16 +1066,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);
@@ -1215,8 +1208,8 @@ int lv_raid_convert(struct logical_volume *lv,
const uint32_t new_region_size,
struct dm_list *allocate_pvs);
int lv_raid_rebuild(struct logical_volume *lv, struct dm_list *rebuild_pvs);
int lv_raid_replace(struct logical_volume *lv, int force,
struct dm_list *remove_pvs, struct dm_list *allocate_pvs);
int lv_raid_replace(struct logical_volume *lv, struct dm_list *remove_pvs,
struct dm_list *allocate_pvs);
int lv_raid_remove_missing(struct logical_volume *lv);
int partial_raid_lv_supports_degraded_activation(const struct logical_volume *lv);
/* -- metadata/raid_manip.c */

View File

@@ -266,16 +266,19 @@ static int _deactivate_and_remove_lvs(struct volume_group *vg, struct dm_list *r
*
* Returns: 1 if in-sync, 0 otherwise.
*/
#define _RAID_IN_SYNC_RETRIES 6
static int _raid_in_sync(struct logical_volume *lv)
{
int retries = _RAID_IN_SYNC_RETRIES;
dm_percent_t sync_percent;
if (seg_is_striped(first_seg(lv)))
return 1;
do {
if (!lv_raid_percent(lv, &sync_percent)) {
log_error("Unable to determine sync status of %s/%s.",
lv->vg->name, lv->name);
return 0;
}
if (sync_percent == DM_PERCENT_0) {
/*
* FIXME We repeat the status read here to workaround an
* unresolved kernel bug when we see 0 even though the
@@ -287,34 +290,14 @@ static int _raid_in_sync(struct logical_volume *lv)
lv->vg->name, lv->name);
return 0;
}
if (sync_percent > DM_PERCENT_0)
break;
if (retries == _RAID_IN_SYNC_RETRIES)
if (sync_percent == DM_PERCENT_100)
log_warn("WARNING: Sync status for %s is inconsistent.",
display_lvname(lv));
usleep(500000);
} while (--retries);
}
return (sync_percent == DM_PERCENT_100) ? 1 : 0;
}
/* Check if RaidLV @lv is synced or any raid legs of @lv are not synced */
static int _raid_devs_sync_healthy(struct logical_volume *lv)
{
char *raid_health;
if (!_raid_in_sync(lv))
return 0;
if (!seg_is_raid1(first_seg(lv)))
return 1;
if (!lv_raid_dev_health(lv, &raid_health))
return_0;
return (strchr(raid_health, 'a') || strchr(raid_health, 'D')) ? 0 : 1;
}
/*
* _raid_remove_top_layer
* @lv
@@ -1055,10 +1038,11 @@ static int _extract_image_components(struct lv_segment *seg, uint32_t idx,
seg_type(seg, idx) = AREA_UNASSIGNED;
seg_metatype(seg, idx) = AREA_UNASSIGNED;
if (!(data_lv->name = _generate_raid_name(data_lv, "extracted", -1)))
/* FIXME Remove duplicated prefix? */
if (!(data_lv->name = _generate_raid_name(data_lv, "_extracted", -1)))
return_0;
if (!(meta_lv->name = _generate_raid_name(meta_lv, "extracted", -1)))
if (!(meta_lv->name = _generate_raid_name(meta_lv, "_extracted", -1)))
return_0;
*extracted_rmeta = meta_lv;
@@ -1070,7 +1054,6 @@ static int _extract_image_components(struct lv_segment *seg, uint32_t idx,
/*
* _raid_extract_images
* @lv
* @force: force a replacement in case of primary mirror leg
* @new_count: The absolute count of images (e.g. '2' for a 2-way mirror)
* @target_pvs: The list of PVs that are candidates for removal
* @shift: If set, use _shift_and_rename_image_components().
@@ -1085,8 +1068,7 @@ static int _extract_image_components(struct lv_segment *seg, uint32_t idx,
*
* Returns: 1 on success, 0 on failure
*/
static int _raid_extract_images(struct logical_volume *lv,
int force, uint32_t new_count,
static int _raid_extract_images(struct logical_volume *lv, uint32_t new_count,
struct dm_list *target_pvs, int shift,
struct dm_list *extracted_meta_lvs,
struct dm_list *extracted_data_lvs)
@@ -1154,16 +1136,11 @@ static int _raid_extract_images(struct logical_volume *lv,
!lv_is_on_pvs(seg_metalv(seg, s), target_pvs))
continue;
/*
* Kernel may report raid LV in-sync but still
* image devices may not be in-sync or faulty.
*/
if (!_raid_devs_sync_healthy(lv) &&
(!seg_is_mirrored(seg) || (s == 0 && !force))) {
if (!_raid_in_sync(lv) &&
(!seg_is_mirrored(seg) || (s == 0))) {
log_error("Unable to extract %sRAID image"
" while RAID array is not in-sync%s",
seg_is_mirrored(seg) ? "primary " : "",
seg_is_mirrored(seg) ? " (use --force option to replace)" : "");
" while RAID array is not in-sync",
seg_is_mirrored(seg) ? "primary " : "");
return 0;
}
}
@@ -1208,7 +1185,7 @@ static int _raid_remove_images(struct logical_volume *lv,
if (!removal_lvs)
removal_lvs = &removed_lvs;
if (!_raid_extract_images(lv, 0, new_count, allocate_pvs, 1,
if (!_raid_extract_images(lv, new_count, allocate_pvs, 1,
removal_lvs, removal_lvs)) {
log_error("Failed to extract images from %s/%s",
lv->vg->name, lv->name);
@@ -1398,7 +1375,7 @@ int lv_raid_split(struct logical_volume *lv, const char *split_name,
return_0;
}
if (!_raid_extract_images(lv, 0, new_count, splittable_pvs, 1,
if (!_raid_extract_images(lv, new_count, splittable_pvs, 1,
&removal_lvs, &data_list)) {
log_error("Failed to extract images from %s/%s",
lv->vg->name, lv->name);
@@ -2482,7 +2459,7 @@ static struct lv_segment *_convert_striped_to_raid0(struct logical_volume *lv,
0 /* chunk_size */,
0 /* seg->region_size */, 0u /* extents_copied */ ,
NULL /* pvmove_source_seg */))) {
log_error("Failed to allocate new raid0 segment for LV %s.", display_lvname(lv));
log_error("Failed to allocate new raid0 segement for LV %s.", display_lvname(lv));
return NULL;
}
@@ -2542,51 +2519,42 @@ static struct possible_takeover_reshape_type _possible_takeover_reshape_types[]
{ .current_types = SEG_STRIPED_TARGET, /* linear, i.e. seg->area_count = 1 */
.possible_types = SEG_RAID1,
.current_areas = 1,
.options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
.options = ALLOW_NONE },
{ .current_types = SEG_STRIPED_TARGET, /* linear, i.e. seg->area_count = 1 */
.possible_types = SEG_RAID0|SEG_RAID0_META,
.current_areas = 1,
.options = ALLOW_STRIPE_SIZE },
{ .current_types = SEG_STRIPED_TARGET, /* striped -> raid0*, i.e. seg->area_count > 1 */
{ .current_types = SEG_STRIPED_TARGET, /* striped, i.e. seg->area_count > 1 */
.possible_types = SEG_RAID0|SEG_RAID0_META,
.current_areas = ~0U,
.options = ALLOW_NONE },
{ .current_types = SEG_STRIPED_TARGET, /* striped -> raid4 , i.e. seg->area_count > 1 */
.possible_types = SEG_RAID4,
.current_areas = ~0U,
.options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
/* raid0* -> */
{ .current_types = SEG_RAID0|SEG_RAID0_META, /* seg->area_count = 1 */
.possible_types = SEG_RAID1,
.current_areas = 1,
.options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
{ .current_types = SEG_RAID0|SEG_RAID0_META, /* raid0* -> striped, i.e. seg->area_count > 1 */
.possible_types = SEG_STRIPED_TARGET,
.current_areas = ~0U,
.options = ALLOW_NONE },
{ .current_types = SEG_RAID0|SEG_RAID0_META, /* raid0* -> raid0*, i.e. seg->area_count > 1 */
.possible_types = SEG_RAID0_META|SEG_RAID0,
.current_areas = ~0U,
.options = ALLOW_NONE },
{ .current_types = SEG_RAID0|SEG_RAID0_META, /* raid0* -> raid4, i.e. seg->area_count > 1 */
{ .current_types = SEG_RAID0|SEG_RAID0_META, /* seg->area_count > 1 */
.possible_types = SEG_RAID4,
.current_areas = ~0U,
.options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
/* raid4 -> -> */
{ .current_types = SEG_RAID4, /* raid4 ->striped/raid0*, i.e. seg->area_count > 1 */
.options = ALLOW_NONE },
{ .current_types = SEG_RAID0|SEG_RAID0_META, /* raid0 striped, i.e. seg->area_count > 0 */
.possible_types = SEG_STRIPED_TARGET|SEG_RAID0|SEG_RAID0_META,
.current_areas = ~0U,
.options = ALLOW_NONE },
/* raid1 -> mirror */
/* raid1 -> */
{ .current_types = SEG_RAID1,
.possible_types = SEG_MIRROR,
.possible_types = SEG_RAID1|SEG_MIRROR,
.current_areas = ~0U,
.options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
.options = ALLOW_NONE },
/* mirror -> raid1 with arbitrary number of legs */
{ .current_types = SEG_MIRROR,
.possible_types = SEG_RAID1,
.possible_types = SEG_MIRROR|SEG_RAID1,
.current_areas = ~0U,
.options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
.options = ALLOW_NONE },
{ .current_types = SEG_RAID4,
.possible_types = SEG_STRIPED_TARGET|SEG_RAID0|SEG_RAID0_META,
.current_areas = ~0U,
.options = ALLOW_NONE },
/* END */
{ .current_types = 0 }
@@ -2893,176 +2861,9 @@ static int _raid1_to_mirrored_wrapper(TAKEOVER_FN_ARGS)
allocate_pvs, 1, &removal_lvs);
}
/*
* HM Helper: (raid0_meta -> raid4)
*
* To convert raid0_meta to raid4, which involves shifting the
* parity device to lv segment area 0 and thus changing MD
* array roles, detach the MetaLVs and reload as raid0 in
* order to wipe them then reattach and set back to raid0_meta.
*/
static int _clear_meta_lvs(struct logical_volume *lv)
{
uint32_t s;
struct lv_segment *seg = first_seg(lv);
struct lv_segment_area *tmp_areas;
const struct segment_type *tmp_segtype;
struct dm_list meta_lvs;
struct lv_list *lvl_array, *lvl;
/* Reject non-raid0_meta segment types cautiously */
if (!seg_is_raid0_meta(seg) ||
!seg->meta_areas)
return_0;
if (!(lvl_array = dm_pool_alloc(lv->vg->vgmem, seg->area_count * sizeof(*lvl_array))))
return_0;
dm_list_init(&meta_lvs);
tmp_areas = seg->meta_areas;
/* Extract all MetaLVs listing them on @meta_lvs */
log_debug_metadata("Extracting all MetaLVs of %s to activate as raid0",
display_lvname(lv));
if (!_extract_image_component_sublist(seg, RAID_META, 0, seg->area_count, &meta_lvs, 0))
return_0;
/* Memorize meta areas and segtype to set again after initializing. */
seg->meta_areas = NULL;
tmp_segtype = seg->segtype;
if (!(seg->segtype = get_segtype_from_flag(lv->vg->cmd, SEG_RAID0)) ||
!lv_update_and_reload(lv))
return_0;
/*
* Now deactivate the MetaLVs before clearing, so
* that _clear_lvs() will activate them visible.
*/
log_debug_metadata("Deactivating pulled out MetaLVs of %s before initializing.",
display_lvname(lv));
dm_list_iterate_items(lvl, &meta_lvs)
if (!deactivate_lv(lv->vg->cmd, lvl->lv))
return_0;
log_debug_metadata("Clearing allocated raid0_meta metadata LVs for conversion to raid4");
if (!_clear_lvs(&meta_lvs)) {
log_error("Failed to initialize metadata LVs");
return 0;
}
/* Set memorized meta areas and raid0_meta segtype */
seg->meta_areas = tmp_areas;
seg->segtype = tmp_segtype;
log_debug_metadata("Adding metadata LVs back into %s", display_lvname(lv));
s = 0;
dm_list_iterate_items(lvl, &meta_lvs) {
lv_set_hidden(lvl->lv);
if (!set_lv_segment_area_lv(seg, s++, lvl->lv, 0, RAID_META))
return 0;
}
return 1;
}
/*
* HM Helper: (raid0* <-> raid4)
*
* Rename SubLVs (pairs) allowing to shift names w/o collisions with active ones.
*/
#define SLV_COUNT 2
static int _rename_area_lvs(struct logical_volume *lv, const char *suffix)
{
uint32_t s;
size_t sz = strlen("rimage") + (suffix ? strlen(suffix) : 0) + 1;
char *sfx[SLV_COUNT] = { NULL, NULL };
struct lv_segment *seg = first_seg(lv);
/* Create _generate_raid_name() suffixes w/ or w/o passed in @suffix */
for (s = 0; s < SLV_COUNT; s++)
if (!(sfx[s] = dm_pool_alloc(lv->vg->cmd->mem, sz)) ||
dm_snprintf(sfx[s], sz, suffix ? "%s%s" : "%s", s ? "rmeta" : "rimage", suffix) < 0)
return_0;
/* Change names (temporarily) to be able to shift numerical name suffixes */
for (s = 0; s < seg->area_count; s++) {
if (!(seg_lv(seg, s)->name = _generate_raid_name(lv, sfx[0], s)))
return_0;
if (seg->meta_areas &&
!(seg_metalv(seg, s)->name = _generate_raid_name(lv, sfx[1], s)))
return_0;
}
for (s = 0; s < SLV_COUNT; s++)
dm_pool_free(lv->vg->cmd->mem, sfx[s]);
return 1;
}
/*
* HM Helper: (raid0* <-> raid4)
*
* Switch area LVs in lv segment @seg indexed by @s1 and @s2
*/
static void _switch_area_lvs(struct lv_segment *seg, uint32_t s1, uint32_t s2)
{
struct logical_volume *lvt;
lvt = seg_lv(seg, s1);
seg_lv(seg, s1) = seg_lv(seg, s2);
seg_lv(seg, s2) = lvt;
/* Be cautious */
if (seg->meta_areas) {
lvt = seg_metalv(seg, s1);
seg_metalv(seg, s1) = seg_metalv(seg, s2);
seg_metalv(seg, s2) = lvt;
}
}
/*
* HM Helper:
*
* shift range of area LVs in @seg in range [ @s1, @s2 ] up if @s1 < @s2,
* else down bubbling the parity SubLVs up/down whilst shifting.
*/
static void _shift_area_lvs(struct lv_segment *seg, uint32_t s1, uint32_t s2)
{
uint32_t s;
if (s1 < s2)
/* Forward shift n+1 -> n */
for (s = s1; s < s2; s++)
_switch_area_lvs(seg, s, s + 1);
else
/* Reverse shift n-1 -> n */
for (s = s1; s > s2; s--)
_switch_area_lvs(seg, s, s - 1);
}
/*
* Switch position of first and last area lv within
* @lv to move parity SubLVs from end to end.
*
* Direction depends on segment type raid4 / raid0_meta.
*/
static int _shift_parity_dev(struct lv_segment *seg)
{
if (seg_is_raid0_meta(seg))
_shift_area_lvs(seg, seg->area_count - 1, 0);
else if (seg_is_raid4(seg))
_shift_area_lvs(seg, 0, seg->area_count - 1);
else
return 0;
return 1;
}
/* raid45 -> raid0* / striped */
static int _raid456_to_raid0_or_striped_wrapper(TAKEOVER_FN_ARGS)
{
int rename_sublvs = 0;
struct lv_segment *seg = first_seg(lv);
struct dm_list removal_lvs;
@@ -3078,39 +2879,10 @@ static int _raid456_to_raid0_or_striped_wrapper(TAKEOVER_FN_ARGS)
if (!_raid_in_sync(lv))
return 0;
if (!yes && yes_no_prompt("Are you sure you want to convert \"%s\" LV %s to \"%s\" "
"type losing all resilience? [y/n]: ",
lvseg_name(seg), display_lvname(lv), new_segtype->name) == 'n') {
log_error("Logical volume %s NOT converted to \"%s\"",
display_lvname(lv), new_segtype->name);
return 0;
}
if (sigint_caught())
return_0;
/* Archive metadata */
if (!archive(lv->vg))
return_0;
/*
* raid4 (which actually gets mapped to raid5/dedicated first parity disk)
* needs shifting of SubLVs to move the parity SubLV pair in the first area
* to the last one before conversion to raid0[_meta]/striped to allow for
* SubLV removal from the end of the areas arrays.
*/
if (seg_is_raid4(seg)) {
/* Shift parity SubLV pair "PDD..." -> "DD...P" to be able to remove it off the end */
if (!_shift_parity_dev(seg))
return 0;
if (segtype_is_any_raid0(new_segtype) &&
!(rename_sublvs = _rename_area_lvs(lv, "_"))) {
log_error("Failed to rename %s LV %s MetaLVs", lvseg_name(seg), display_lvname(lv));
return 0;
}
}
/* Remove meta and data LVs requested */
if (!_lv_raid_change_image_count(lv, new_image_count, allocate_pvs, &removal_lvs, 0, 0))
return 0;
@@ -3130,19 +2902,7 @@ static int _raid456_to_raid0_or_striped_wrapper(TAKEOVER_FN_ARGS)
seg->region_size = 0;
if (!_lv_update_reload_fns_reset_eliminate_lvs(lv, &removal_lvs))
return_0;
if (rename_sublvs) {
if (!_rename_area_lvs(lv, NULL)) {
log_error("Failed to rename %s LV %s MetaLVs", lvseg_name(seg), display_lvname(lv));
return 0;
}
if (!lv_update_and_reload(lv))
return_0;
}
return 1;
return _lv_update_reload_fns_reset_eliminate_lvs(lv, &removal_lvs);
}
static int _striped_to_raid0_wrapper(struct logical_volume *lv,
@@ -3170,9 +2930,6 @@ static int _striped_to_raid0_wrapper(struct logical_volume *lv,
static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS)
{
struct lv_segment *seg = first_seg(lv);
struct dm_list removal_lvs;
dm_list_init(&removal_lvs);
if (seg_is_raid10(seg))
return _takeover_unsupported_yet(lv, new_stripes, new_segtype);
@@ -3187,13 +2944,6 @@ static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS)
return 0;
}
/* FIXME: restricted to raid4 for the time being... */
if (!segtype_is_raid4(new_segtype)) {
/* Can't convert striped/raid0* to e.g. raid10_offset */
log_error("Can't convert %s to %s", display_lvname(lv), new_segtype->name);
return 0;
}
/* Archive metadata */
if (!archive(lv->vg))
return_0;
@@ -3211,10 +2961,7 @@ static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS)
log_debug_metadata("Adding metadata LVs to %s", display_lvname(lv));
if (!_raid0_add_or_remove_metadata_lvs(lv, 1 /* update_and_reload */, allocate_pvs, NULL))
return 0;
/* raid0_meta -> raid4 needs clearing of MetaLVs in order to avoid raid disk role cahnge issues in the kernel */
} else if (segtype_is_raid4(new_segtype) &&
!_clear_meta_lvs(lv))
return 0;
}
/* Add the additional component LV pairs */
log_debug_metadata("Adding %" PRIu32 " component LV pair(s) to %s", new_image_count - lv_raid_image_count(lv),
@@ -3222,9 +2969,8 @@ static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS)
if (!_lv_raid_change_image_count(lv, new_image_count, allocate_pvs, NULL, 0, 1))
return 0;
if (segtype_is_raid4(new_segtype) &&
(!_shift_parity_dev(seg) ||
!_rename_area_lvs(lv, "_"))) {
if (!segtype_is_raid4(new_segtype)) {
/* Can't convert striped/raid0* to e.g. raid10_offset */
log_error("Can't convert %s to %s", display_lvname(lv), new_segtype->name);
return 0;
}
@@ -3241,14 +2987,6 @@ static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS)
if (!_lv_update_reload_fns_reset_eliminate_lvs(lv, NULL))
return_0;
if (segtype_is_raid4(new_segtype)) {
/* We had to rename SubLVs because of collision free sgifting, rename back... */
if (!_rename_area_lvs(lv, NULL))
return 0;
if (!lv_update_and_reload(lv))
return_0;
}
return 1;
}
@@ -3892,7 +3630,6 @@ has_enough_space:
* new SubLVS are allocated on PVs on list @allocate_pvs.
*/
static int _lv_raid_rebuild_or_replace(struct logical_volume *lv,
int force,
struct dm_list *remove_pvs,
struct dm_list *allocate_pvs,
int rebuild)
@@ -4067,8 +3804,7 @@ try_again:
* supplied - knowing that only the image with the error target
* will be affected.
*/
if (!_raid_extract_images(lv, force,
raid_seg->area_count - match_count,
if (!_raid_extract_images(lv, raid_seg->area_count - match_count,
partial_segment_removed ?
&lv->vg->pvs : remove_pvs, 0,
&old_lvs, &old_lvs)) {
@@ -4173,7 +3909,7 @@ skip_alloc:
int lv_raid_rebuild(struct logical_volume *lv,
struct dm_list *rebuild_pvs)
{
return _lv_raid_rebuild_or_replace(lv, 0, rebuild_pvs, NULL, 1);
return _lv_raid_rebuild_or_replace(lv, rebuild_pvs, NULL, 1);
}
/*
@@ -4186,11 +3922,10 @@ int lv_raid_rebuild(struct logical_volume *lv,
* allocating new SubLVs from PVs on list @allocate_pvs.
*/
int lv_raid_replace(struct logical_volume *lv,
int force,
struct dm_list *remove_pvs,
struct dm_list *allocate_pvs)
{
return _lv_raid_rebuild_or_replace(lv, force, remove_pvs, allocate_pvs, 0);
return _lv_raid_rebuild_or_replace(lv, remove_pvs, allocate_pvs, 0);
}
int lv_raid_remove_missing(struct logical_volume *lv)

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -268,7 +268,6 @@ struct segment_type *init_unknown_segtype(struct cmd_context *cmd,
#define RAID_FEATURE_RAID10 (1U << 0) /* version 1.3 */
#define RAID_FEATURE_RAID0 (1U << 1) /* version 1.7 */
#define RAID_FEATURE_RESHAPING (1U << 2) /* version 1.8 */
#define RAID_FEATURE_RAID4 (1U << 3) /* ! version 1.8 or 1.9.0 */
#ifdef RAID_INTERNAL
int init_raid_segtypes(struct cmd_context *cmd, struct segtype_library *seglib);

View File

@@ -748,19 +748,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

@@ -15,8 +15,6 @@
#define LVM_DBUS_DESTINATION "com.redhat.lvmdbus1"
#define LVM_DBUS_PATH "/com/redhat/lvmdbus1/Manager"
#define LVM_DBUS_INTERFACE "com.redhat.lvmdbus1.Manager"
#define SD_BUS_SYSTEMD_NO_SUCH_UNIT_ERROR "org.freedesktop.systemd1.NoSuchUnit"
#define SD_BUS_DBUS_SERVICE_UNKNOWN_ERROR "org.freedesktop.DBus.Error.ServiceUnknown"
#ifdef NOTIFYDBUS_SUPPORT
#include <systemd/sd-bus.h>
@@ -28,7 +26,6 @@ int lvmnotify_is_supported(void)
void lvmnotify_send(struct cmd_context *cmd)
{
static const char _dbus_notification_failed_msg[] = "D-Bus notification failed";
sd_bus *bus = NULL;
sd_bus_message *m = NULL;
sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -64,11 +61,7 @@ void lvmnotify_send(struct cmd_context *cmd)
cmd_name);
if (ret < 0) {
if (sd_bus_error_has_name(&error, SD_BUS_SYSTEMD_NO_SUCH_UNIT_ERROR) ||
sd_bus_error_has_name(&error, SD_BUS_DBUS_SERVICE_UNKNOWN_ERROR))
log_debug_dbus("%s: %s", _dbus_notification_failed_msg, error.message);
else
log_warn("WARNING: %s: %s", _dbus_notification_failed_msg, error.message);
log_warn("WARNING: D-Bus notification failed: %s", error.message);
goto out;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2016 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2013 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -366,7 +366,7 @@ static int _raid_target_present(struct cmd_context *cmd,
static int _raid_checked = 0;
static int _raid_present = 0;
static unsigned _raid_attrs = 0;
static int _raid_attrs = 0;
uint32_t maj, min, patchlevel;
unsigned i;
@@ -389,12 +389,6 @@ static int _raid_target_present(struct cmd_context *cmd,
else
log_very_verbose("Target raid does not support %s.",
_features[i].feature);
if (!(maj == 1 && (min == 8 || (min == 9 && patchlevel == 0))))
_raid_attrs |= RAID_FEATURE_RAID4;
else
log_very_verbose("Target raid does not support %s.",
SEG_TYPE_NAME_RAID4);
}
if (attributes)

View File

@@ -114,9 +114,9 @@ static void _default_log_line(int level,
const char *f, va_list ap)
{
static int _abort_on_internal_errors = -1;
FILE *out = log_stderr(level) ? stderr : stdout;
FILE *out = (level & _LOG_STDERR) ? stderr : stdout;
level = log_level(level);
level &= ~(_LOG_STDERR | _LOG_BYPASS_REPORT);
if (level <= _LOG_WARN || _verbose) {
if (level < _LOG_WARN)
@@ -137,7 +137,8 @@ static void _default_log_line(int level,
__attribute__((format(printf, 5, 6)))
static void _default_log_with_errno(int level,
const char *file, int line, int dm_errno_or_class,
const char *file __attribute__((unused)),
int line __attribute__((unused)), int dm_errno_or_class,
const char *f, ...)
{
va_list ap;
@@ -161,75 +162,29 @@ static void _default_log(int level, const char *file,
dm_log_fn dm_log = _default_log;
dm_log_with_errno_fn dm_log_with_errno = _default_log_with_errno;
/*
* Wrapper function to reformat new messages to and
* old style logging which had not used errno parameter
*
* As we cannot simply pass '...' to old function we
* need to process arg list locally and just pass '%s' + buffer
*/
__attribute__((format(printf, 5, 6)))
static void _log_to_default_log(int level,
const char *file, int line, int dm_errno_or_class,
const char *f, ...)
{
va_list ap;
char buf[2 * PATH_MAX + 256]; /* big enough for most messages */
va_start(ap, f);
vsnprintf(buf, sizeof(buf), f, ap);
va_end(ap);
dm_log(level, file, line, "%s", buf);
}
/*
* Wrapper function take 'old' style message without errno
* and log it via new logging function with errno arg
*
* This minor case may happen if new libdm is used with old
* recompiled tool that would decided to use new logging,
* but still would like to use old binary plugins.
*/
__attribute__((format(printf, 4, 5)))
static void _log_to_default_log_with_errno(int level,
const char *file, int line, const char *f, ...)
{
va_list ap;
char buf[2 * PATH_MAX + 256]; /* big enough for most messages */
va_start(ap, f);
vsnprintf(buf, sizeof(buf), f, ap);
va_end(ap);
dm_log_with_errno(level, file, line, 0, "%s", buf);
}
void dm_log_init(dm_log_fn fn)
{
if (fn) {
if (fn)
dm_log = fn;
dm_log_with_errno = _log_to_default_log;
} else {
else
dm_log = _default_log;
dm_log_with_errno = _default_log_with_errno;
}
dm_log_with_errno = _default_log_with_errno;
}
int dm_log_is_non_default(void)
{
return (dm_log == _default_log && dm_log_with_errno == _default_log_with_errno) ? 0 : 1;
return (dm_log == _default_log) ? 0 : 1;
}
void dm_log_with_errno_init(dm_log_with_errno_fn fn)
{
if (fn) {
dm_log = _log_to_default_log_with_errno;
if (fn)
dm_log_with_errno = fn;
} else {
dm_log = _default_log;
else
dm_log_with_errno = _default_log_with_errno;
}
dm_log = _default_log;
}
void dm_log_init_verbose(int level)

View File

@@ -3881,7 +3881,7 @@ merge:
continue;
if (_extents_overlap(ext, next)) {
log_warn("WARNING: region IDs " FMTu64 " and "
log_warn("Warning: region IDs " FMTu64 " and "
FMTu64 " overlap. Some events will be "
"counted twice.", ext->id, next->id);
/* merge larger extent into smaller */
@@ -4002,11 +4002,11 @@ int dm_stats_create_group(struct dm_stats *dms, const char *members,
}
if (precise && (precise != count))
log_warn("WARNING: Grouping regions with different clock resolution: "
"precision may be lost.");
log_warn("Grouping regions with different clock resolution: "
"precision may be lost");
if (!_stats_group_check_overlap(dms, regions, count))
log_very_verbose("Creating group with overlapping regions.");
log_info("Creating group with overlapping regions");
if (!_stats_create_group(dms, regions, alias, group_id))
goto bad;
@@ -4048,7 +4048,7 @@ int dm_stats_delete_group(struct dm_stats *dms, uint64_t group_id,
if (dm_bit(regions, i)) {
dm_bit_clear(regions, i);
if (remove_regions && !dm_stats_delete_region(dms, i))
log_warn("WARNING: Failed to delete region "
log_warn("Failed to delete region "
FMTu64 " on %s.", i, dms->name);
}
}
@@ -4142,7 +4142,7 @@ static int _stats_group_file_regions(struct dm_stats *dms, uint64_t *region_ids,
* returned by FIEMAP imply a kernel bug or a corrupt fs.
*/
if (!_stats_group_check_overlap(dms, regions, count))
log_very_verbose("Creating group with overlapping regions.");
log_info("Creating group with overlapping regions.");
if (!_stats_create_group(dms, regions, alias, &group_id))
goto bad;

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -18,10 +18,16 @@
#include "libdevmapper.h"
extern dm_log_fn dm_log;
extern dm_log_with_errno_fn dm_log_with_errno;
#define LOG_MESG(l, f, ln, e, x...) \
dm_log_with_errno(l, f, ln, e, ## x)
do { \
if (dm_log_is_non_default()) \
dm_log(l, f, ln, ## x); \
else \
dm_log_with_errno(l, f, ln, e, ## x); \
} while (0)
#define LOG_LINE(l, x...) LOG_MESG(l, __FILE__, __LINE__, 0, ## x)
#define LOG_LINE_WITH_ERRNO(l, e, x...) LOG_MESG(l, __FILE__, __LINE__, e, ## x)

View File

@@ -365,9 +365,6 @@ See corresponding operation --splitmirrors.
VG/RaidLV
.br
\[bu]
Options \-\-background, \-\-interval.
.br
\[bu]
Replace failed PVs in RaidLV.
.B lvconvert \-\-replace
@@ -505,9 +502,6 @@ Change the type of log used by MirrorLV.
VG/MirrorLV
.br
\[bu]
Options \-\-background, \-\-interval.
.br
\[bu]
Replace failed PVs in MirrorLV.
.B lvconvert \-\-type linear

View File

@@ -34,7 +34,6 @@ TOOL=blkdeactivate
DEV_DIR='/dev'
SYS_BLK_DIR='/sys/block'
MOUNTPOINT="/bin/mountpoint"
UMOUNT="/bin/umount"
DMSETUP="@sbindir@/dmsetup"
LVM="@sbindir@/lvm"
@@ -158,11 +157,9 @@ device_umount_one() {
echo -n " [UMOUNT]: unmounting $name ($kname) mounted on $mnt... "
if eval $UMOUNT $UMOUNT_OPTS "$(printf "%s" "$mnt")" $OUT $ERR; then
echo "done"
elif $MOUNTPOINT -q "$mnt"; then
else
echo "skipping"
add_device_to_skip_list
else
echo "already unmounted"
fi
else
echo " [SKIP]: unmount of $name ($kname) mounted on $mnt"

View File

@@ -77,9 +77,6 @@ help:
@echo " check_cluster Run tests with cluster daemon."
@echo " check_lvmetad Run tests with lvmetad daemon."
@echo " check_lvmpolld Run tests with lvmpolld daemon."
@echo " check_cluster_lvmpolld Run tests with clvmd and lvmpolld daemon."
@echo " check_lvmetad_lvmpolld Run tests with lvmetad and lvmpolld daemon."
@echo " check_all_lvmpolld Run all tests with lvmpolld daemon."
@echo " check_lvmlockd_sanlock Run tests with lvmlockd and sanlock."
@echo " check_lvmlockd_dlm Run tests with lvmlockd and dlm."
@echo " check_lvmlockd_test Run tests with lvmlockd --test."
@@ -147,21 +144,6 @@ endif
ifeq ("@BUILD_LVMPOLLD@", "yes")
check_lvmpolld: .tests-stamp
VERBOSE=$(VERBOSE) ./lib/runner \
--testdir . --outdir results \
--flavours ndev-lvmpolld --only $(T) --skip $(S)
check_cluster_lvmpolld: .tests-stamp
VERBOSE=$(VERBOSE) ./lib/runner \
--testdir . --outdir results \
--flavours ndev-cluster-lvmpolld --only $(T) --skip $(S)
check_lvmetad_lvmpolld: .tests-stamp
VERBOSE=$(VERBOSE) ./lib/runner \
--testdir . --outdir results \
--flavours ndev-lvmetad-lvmpolld --only $(T) --skip $(S)
check_all_lvmpolld: .tests-stamp
VERBOSE=$(VERBOSE) ./lib/runner \
--testdir . --outdir results \
--flavours ndev-lvmpolld,ndev-cluster-lvmpolld,ndev-lvmetad-lvmpolld --only $(T) --skip $(S)

View File

@@ -1063,7 +1063,7 @@ generate_config() {
cat > "$config_values" <<-EOF
activation/checks = 1
activation/monitoring = 0
activation/polling_interval = 1
activation/polling_interval = 0
activation/retry_deactivation = 1
activation/snapshot_autoextend_percent = 50
activation/snapshot_autoextend_threshold = 50
@@ -1376,15 +1376,6 @@ have_raid() {
esac
}
have_raid4 () {
local r=1
have_raid 1 8 0 && r=0
have_raid 1 9 1 && r=1
return $r
}
have_cache() {
test "$CACHE" = shared -o "$CACHE" = internal || {
echo "Cache is not built-in." >&2

View File

@@ -16,7 +16,7 @@ TEST_RAID=raid456
aux raid456_replace_works || skip
aux have_raid 1 5 2 || skip
aux have_raid4 && run_types raid4 -i 2 "$dev1" "$dev2" "$dev3" "$dev4"
run_types raid4 -i 2 "$dev1" "$dev2" "$dev3" "$dev4"
run_types raid5 -i 2 "$dev1" "$dev2" "$dev3" "$dev4"
run_types raid6 -i 3 "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"

View File

@@ -16,9 +16,6 @@ SKIP_WITH_LVMPOLLD=1
aux have_raid 1 9 0 || skip
correct_raid4_layout=0
aux have_raid 1 9 1 && correct_raid4_layout=1
aux prepare_vg 9 288
# Delay 1st leg so that rebuilding status characters
@@ -81,61 +78,22 @@ aux wait_for_sync $vg $lv1
# Clean up
lvremove --yes $vg/$lv1
# Create 3-way striped
lvcreate -y -aey --type striped -i 3 -L 64M -n $lv1 $vg
check lv_field $vg/$lv1 segtype "striped"
# Create 3-way raid0
lvcreate -y -aey --type raid0 -i 3 -L 64M -n $lv1 $vg
check lv_field $vg/$lv1 segtype "raid0"
check lv_field $vg/$lv1 stripes 3
echo y | mkfs -t ext4 /dev/mapper/$vg-$lv1
fsck -fn /dev/mapper/$vg-$lv1
# Create 3-way raid0
lvcreate -y -aey --type raid0 -i 3 -L 64M -n $lv2 $vg
check lv_field $vg/$lv2 segtype "raid0"
check lv_field $vg/$lv2 stripes 3
echo y | mkfs -t ext4 /dev/mapper/$vg-$lv2
fsck -fn /dev/mapper/$vg-$lv2
# Create 3-way raid0_meta
lvcreate -y -aey --type raid0_meta -i 3 -L 64M -n $lv3 $vg
check lv_field $vg/$lv3 segtype "raid0_meta"
check lv_field $vg/$lv3 stripes 3
echo y | mkfs -t ext4 /dev/mapper/$vg-$lv3
fsck -fn /dev/mapper/$vg-$lv3
if [ $correct_raid4_layout -eq 1 ]
then
# Create 3-way raid4
lvcreate -y -aey --type raid4 -i 3 -L 64M -n $lv4 $vg
check lv_field $vg/$lv4 segtype "raid4"
check lv_field $vg/$lv4 stripes 4
echo y | mkfs -t ext4 /dev/mapper/$vg-$lv4
fsck -fn /dev/mapper/$vg-$lv4
aux wait_for_sync $vg $lv4
fsck -fn /dev/mapper/$vg-$lv4
# Convert raid4 -> striped (correct raid4 mapping test!)
lvconvert -y --ty striped $vg/$lv4
check lv_field $vg/$lv4 segtype "striped"
check lv_field $vg/$lv4 stripes 3
fsck -fn /dev/mapper/$vg-$lv4
# Convert striped -> raid4
# Convert raid0 -> raid4
lvconvert -y --ty raid4 $vg/$lv1
lvchange --refresh $vg/$lv1
check lv_field $vg/$lv1 segtype "raid4"
check lv_field $vg/$lv1 stripes 4
fsck -fn /dev/mapper/$vg-$lv1
aux wait_for_sync $vg $lv1
fsck -fn /dev/mapper/$vg-$lv1
# Convert raid0 -> raid4
lvconvert -y --ty raid4 $vg/$lv2
check lv_field $vg/$lv2 segtype "raid4"
check lv_field $vg/$lv2 stripes 4
fsck -fn /dev/mapper/$vg-$lv2
aux wait_for_sync $vg $lv2
fsck -fn /dev/mapper/$vg-$lv2
# Convert raid4 -> raid0_meta
lvconvert -y --ty raid0_meta $vg/$lv1
check lv_field $vg/$lv1 segtype "raid0_meta"
@@ -158,24 +116,11 @@ fsck -fn /dev/mapper/$vg-$lv1
# Convert raid0 -> raid4
lvconvert -y --ty raid4 $vg/$lv1
lvchange --refresh $vg/$lv1
check lv_field $vg/$lv1 segtype "raid4"
check lv_field $vg/$lv1 stripes 4
fsck -fn /dev/mapper/$vg-$lv1
aux wait_for_sync $vg $lv1
fsck -fn /dev/mapper/$vg-$lv1
# Convert raid4 -> striped
lvconvert -y --ty striped $vg/$lv1
check lv_field $vg/$lv1 segtype "striped"
check lv_field $vg/$lv1 stripes 3
fsck -fn /dev/mapper/$vg-$lv1
else
not lvcreate -y -aey --type raid4 -i 3 -L 64M -n $lv4 $vg
not lvconvert -y --ty raid4 $vg/$lv1
not lvconvert -y --ty raid4 $vg/$lv2
fi
vgremove -ff $vg

View File

@@ -31,11 +31,8 @@ aux have_raid 1 3 0 || skip
aux prepare_pvs 7 # 7 devices for 2 dev replacement of 5-dev RAID6
vgcreate -s 256k $vg $(cat DEVICES)
levels="5 6"
aux have_raid4 && levels="4 5 6"
# RAID 4/5/6 (can replace up to 'parity' devices)
for i in $levels; do
for i in 4 5 6; do
lvcreate --type raid$i -i 3 -l 3 -n $lv1 $vg
if [ $i -eq 6 ]; then

View File

@@ -25,8 +25,7 @@ which "$FSCK" || skip
#
# Main
#
# older versions of cache target reported unreliably write failures
aux have_cache 1 7 0 || skip
aux have_cache 1 5 0 || skip
aux prepare_vg 4

View File

@@ -53,8 +53,7 @@ delay 50
# RAID1 triple-leg single replace during initial sync
lvcreate --type raid1 -m 2 -L $RAID_SIZE -n $lv1 $vg "$dev1" "$dev2" "$dev3"
aux disable_dev "$dev2" "$dev3"
# FIXME 2016/11/04 AGK: Disabled next line as it fails to guarantee it is not already in sync.
#not lvconvert -y --repair $vg/$lv1
not lvconvert -y --repair $vg/$lv1
aux wait_for_sync $vg $lv1
lvconvert -y --repair $vg/$lv1
vgreduce --removemissing $vg

View File

@@ -21,9 +21,6 @@ aux can_use_16T || skip
aux have_raid 1 3 0 || skip
segtypes="raid5"
aux have_raid4 && segtypes="raid4 raid5"
# Prepare 5x ~1P sized devices
aux prepare_pvs 5 1000000000
@@ -56,7 +53,7 @@ check raid_leg_status $vg1 $lv1 "AA"
lvremove -ff $vg1
# 750 TiB raid4/5
for segtype in $segtypes; do
for segtype in raid4 raid5; do
lvcreate --type $segtype -i 3 -L 750T -n $lv1 $vg1 --nosync
check lv_field $vg1/$lv1 size "750.00t"
check raid_leg_status $vg1 $lv1 "AAAA"

View File

@@ -16,20 +16,17 @@ SKIP_WITH_LVMPOLLD=1
aux have_raid 1 7 0 || skip
segtypes=raid5
aux have_raid4 && segtypes="raid4 raid5"
aux prepare_vg 6
# 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 10 $(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 --yes --type raid0 -i 3 -l 1 -n $lv1 $vg
check raid_leg_status $vg $lv1 "AAA"
lvremove --yes $vg/$lv1
done
@@ -46,8 +43,8 @@ lvcreate --yes --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
for r in raid4 raid5
do
# raid4/5 support resynchronization
lvcreate --yes --type $r -i 3 -l 2 -n $lv1 $vg
check raid_leg_status $vg $lv1 "aaaa"

View File

@@ -23,9 +23,6 @@ lv_devices() {
########################################################
aux have_raid 1 3 0 || skip
RAID4=""
aux have_raid4 && RAID4=raid4
aux prepare_pvs 6 20 # 6 devices for RAID10 (2-mirror,3-stripe) test
vgcreate -s 512k $vg $(cat DEVICES)
@@ -57,7 +54,7 @@ aux wait_for_sync $vg $lv1
lvremove -ff $vg
# Create RAID 4/5/6 (explicit 3-stripe + parity devs)
for i in $RAID4 \
for i in raid4 \
raid5 raid5_ls raid5_la raid5_rs raid5_ra \
raid6 raid6_zr raid6_nr raid6_nc; do
@@ -67,7 +64,7 @@ for i in $RAID4 \
done
# Create RAID 4/5/6 (explicit 3-stripe + parity devs) - Set min/max recovery
for i in $RAID4 \
for i in raid4 \
raid5 raid5_ls raid5_la raid5_rs raid5_ra \
raid6 raid6_zr raid6_nr raid6_nc; do

View File

@@ -24,28 +24,6 @@ pvscan --cache
vgs | grep $vg1
# Check that an LV cannot be activated by lvchange while VG is exported
lvcreate -n $lv1 -l 4 -a n $vg1
check lv_exists $vg1
vgexport $vg1
fail lvs $vg1
fail lvchange -ay $vg1/$lv1
vgimport $vg1
check lv_exists $vg1
check lv_field $vg/$lv1 lv_active ""
# Check that an LV cannot be activated by pvscan while VG is exported
vgexport $vg1
pvscan --cache -aay "$dev1"
pvscan --cache -aay "$dev2"
vgimport $vg1
check lv_exists $vg1
check lv_field $vg1/$lv1 lv_active ""
pvscan --cache -aay "$dev1"
pvscan --cache -aay "$dev2"
check lv_field $vg1/$lv1 lv_active "active"
lvchange -an $vg1/$lv1
# When MDA is ignored on PV, do not read any VG
# metadata from such PV as it may contain old
# metadata which hasn't been updated for some

View File

@@ -16,9 +16,6 @@ SKIP_WITH_LVMPOLLD=1
aux have_raid 1 3 0 || skip
levels="5 6"
aux have_raid4 && levels="4 5 6"
aux prepare_pvs 6 80
vgcreate -s 256K $vg $(cat DEVICES)
@@ -40,7 +37,7 @@ for deactivate in true false; do
#check raid_images_contiguous $vg $lv1
# Extend and reduce 3-striped RAID 4/5/6
for i in $levels ; do
for i in 4 5 6 ; do
lvcreate --type raid$i -i 3 -l 3 -n $lv2 $vg
test $deactivate && {
@@ -62,7 +59,7 @@ done
# Bug 1005434
# Ensure extend is contiguous
lvcreate --type raid5 -l 2 -i 2 -n $lv1 $vg "$dev4" "$dev5" "$dev6"
lvcreate --type raid4 -l 2 -i 2 -n $lv1 $vg "$dev4" "$dev5" "$dev6"
lvextend -l +2 --alloc contiguous $vg/$lv1
check lv_tree_on $vg $lv1 "$dev4" "$dev5" "$dev6"

View File

@@ -76,7 +76,7 @@ test_pvmove_resume() {
aux enable_dev "$dev2"
i=0
while get lv_field $vg name -a | egrep "^\[?pvmove"; do
while get lv_field $vg name -a | grep "^pvmove"; do
# wait for 30 secs at max
test $i -ge 300 && die "Pvmove is too slow or does not progress."
sleep .1

View File

@@ -89,7 +89,7 @@ test_pvmove_resume() {
aux enable_dev "$dev5"
i=0
while get lv_field $vg name -a | egrep "^\[?pvmove"; do
while get lv_field $vg name -a | grep "^\[?pvmove"; do
# wait for 30 secs at max
test $i -ge 300 && die "Pvmove is too slow or does not progress."
sleep .1

View File

@@ -40,14 +40,13 @@ snap_and_merge() {
kill $SLEEP_PID
aux delay_dev "$dev1" 0 200 $(get first_extent_sector "$dev1"):
lvchange --poll n --refresh $vg/$lv1
lvchange --refresh $vg/$lv1
dmsetup table
lvs -a -o+lv_merging,lv_merge_failed $vg
sleep 1
check lv_attr_bit state $vg/$lv1 "a"
check lv_attr_bit state $vg/$lv2 "a"
aux error_dev "$dev2" $(get first_extent_sector "$dev2"):
aux enable_dev "$dev1"
# delay to let snapshot merge 'discover' failing COW device
sleep 1
sync
@@ -57,7 +56,7 @@ snap_and_merge() {
check lv_attr_bit state $vg/$lv2 "m"
# device OK and running in full speed
aux enable_dev "$dev2"
aux enable_dev "$dev1" "$dev2"
# reactivate so merge can finish
lvchange -an $vg

View File

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

@@ -17,8 +17,6 @@
* Put all long args that don't have a corresponding short option first.
*/
/* *INDENT-OFF* */
arg(ARG_UNUSED, '-', "", 0, 0, 0) /* place holder for unused 0 value */
arg(abort_ARG, '\0', "abort", 0, 0, 0)
arg(activationmode_ARG, '\0', "activationmode", activationmode_VAL, 0, 0)
arg(addtag_ARG, '\0', "addtag", tag_VAL, ARG_GROUPABLE, 0)
@@ -60,7 +58,6 @@ arg(locktype_ARG, '\0', "locktype", locktype_VAL, 0, 0)
arg(logonly_ARG, '\0', "logonly", 0, 0, 0)
arg(maxrecoveryrate_ARG, '\0', "maxrecoveryrate", sizekb_VAL, 0, 0)
arg(merge_ARG, '\0', "merge", 0, 0, 0)
arg(mergesnapshot_ARG, '\0', "mergesnapshot", 0, 0, 0)
arg(mergedconfig_ARG, '\0', "mergedconfig", 0, 0, 0)
arg(metadatacopies_ARG, '\0', "metadatacopies", metadatacopies_VAL, 0, 0)
arg(metadataignore_ARG, '\0', "metadataignore", bool_VAL, 0, 0)

View File

@@ -3,8 +3,8 @@
# and tools/command-lines-count.h must be regenerated
# with:
#
# tools/create-commands --output count tools/command-lines.in > tools/command-lines-count.h
# tools/create-commands --output struct tools/command-lines.in > tools/command-lines.h
# scripts/create-commands --output count scripts/command-lines.in > tools/command-lines-count.h
# scripts/create-commands --output struct scripts/command-lines.in > tools/command-lines.h
#
#
@@ -83,13 +83,6 @@
# Also, --thinpool VG/LV or --cachepool VG/LV can be used in
# place of --name to provide the VG name instead of pos 1.
#
# Note that one the most difficult aspect of these definitions is
# the variants of --thin / --type thin / --type thin-pool,
# --cache / --type cache / --type cache-pool.
# There are no consistent rules to follow and the behaviors are
# unpredictable; each possible variation and combination needs
# to be tested individually to see what it means.
#
# Some options have multiple names, but only one form of the name
# is used in these definitions. Synonyms will be recognized when
# matching a command to a command definition.
@@ -122,42 +115,25 @@
# included in the text as indicators of new lines when printing
# the descriptions for help/man output.
#
# RULE: rules that a given command must follow, i.e. required (and)
# or invalid (not) combinations of options, LV types or LV properties.
# Note that one the most difficult aspect of these definitions is
# the variants of --thin / --type thin / --type thin-pool,
# --cache / --type cache / --type cache-pool.
# There are no consistent rules to follow and the behaviors are
# unpredictable; each possible variation and combination needs
# to be tested individually to see what it means.
#
# RULE: A and|not B
# Another capability we might want to add here is a way to express
# rules, per definition, of what arg combinations are allowed or
# required, e.g.
#
# Conditions in A are applied to a given command+LV.
# If the conditions in A are true, then the checks in B
# are applied. If the checks in B are true|false according
# to and|not, then the command fails|continues.
# if --foo is set, then --bar cannot be set could be encoded as:
# RULE_OPT_INCOMPAT_OPT: --foo --bar
#
# When A is "all", the conditions in B are always applied.
#
# Conditions:
# . if any --option listed is set, the checks may apply
# . if any LV_type listed matches LV, the checks may apply
# . if all lv_is_prop listed matches LV, the checks may apply
# . if all of the above pass, then perform the checks
#
# Checks for "and":
# . if any --option listed is not set, then fail
# . if none of the LV_types matches the LV, then fail
# . if any of the lv_is_prop do not match the LV, then fail
#
# Checks for "not":
# . if any --option listed is set, then fail
# . if any of the LV_types matches the LV, then fail
# . if any of the lv_is_prop match the LV, then fail
#
# RULE: --option|LV_type|lv_is_prop|all ... and|not --option|LV_type|lv_is_prop ...
#
# RULE: --opt1 not --opt2
# RULE: --opt1 and --opt2
# RULE: --opt1 LV_type1 lv_is_prop1 and --opt2
# RULE: --opt1 LV_type1 and lv_is_prop1
# RULE: LV_type1 and lv_is_prop1
# if --foo is set, then --bar is required could be encoded as:
# RULE_OPT_REQUIRES_OPT: --foo --bar
#
# if --foo is set, then positional arg 1 is required
# RULE_OPT_REQUIRES_POS: --foo 1
#
#
@@ -222,9 +198,9 @@ OO_CONFIG: --atversion String, --typeconfig ConfigType, --file String, --ignorea
# None of these can function as a required option for lvchange.
OO_LVCHANGE: --autobackup Bool, --force, --ignoremonitoring,
--ignoreskippedcluster, --noudevsync, --reportformat ReportFmt,
--select String
OO_LVCHANGE: --autobackup Bool, --force, --ignorelockingfailure,
--ignoremonitoring, --ignoreskippedcluster, --noudevsync,
--reportformat ReportFmt, --sysinit, --select String
# Any of these can function as a required option for lvchange.
# profile is also part of OO_ALL, but is repeated in OO_LVCHANGE_META
@@ -237,48 +213,30 @@ OO_LVCHANGE_META: --addtag Tag, --deltag Tag,
--errorwhenfull Bool, --discards Discards, --zero Bool,
--cachemode CacheMode, --cachepolicy String, --cachesettings String,
--minrecoveryrate SizeKB, --maxrecoveryrate SizeKB,
--writebehind Number, --writemostly WriteMostlyPV, --persistent n
--writebehind Number, --writemostly WriteMostlyPV
lvchange OO_LVCHANGE_META VG|LV|Tag|Select ...
OO: OO_LVCHANGE
ID: lvchange_properties
DESC: Change a general LV property.
RULE: all not lv_is_pvmove lv_is_mirror_log lv_is_mirror_image
RULE: all and lv_is_vg_writable
RULE: --contiguous not --alloc
RULE: --profile not --detachprofile
RULE: --metadataprofile not --detachprofile
RULE: --minrecoveryrate --maxrecoveryrate and LV_raid
RULE: --writebehind --writemostly and LV_raid1
RULE: --cachemode --cachepolicy --cachesettings and LV_cache LV_cachepool
RULE: --errorwhenfull --discards --zero and LV_thinpool
RULE: --permission not lv_is_external_origin lv_is_raid_metadata lv_is_raid_image LV_thinpool
RULE: --alloc --contiguous --metadataprofile --permission --persistent --profile --readahead not lv_is_thick_origin
RULE: --alloc --discards --zero --cachemode --cachepolicy --cachesettings not lv_is_partial
lvchange --resync VG|LV_raid_mirror|Tag|Select ...
OO: OO_LVCHANGE
ID: lvchange_resync
DESC: Resyncronize a mirror or raid LV.
RULE: all not lv_is_pvmove lv_is_locked
RULE: all not LV_raid0
lvchange --syncaction SyncAction VG|LV_raid|Tag|Select ...
OO: OO_LVCHANGE
ID: lvchange_syncaction
DESC: Resynchronize or check a raid LV.
RULE: all not LV_raid0
lvchange --rebuild PV VG|LV_raid|Tag|Select ...
OO: OO_LVCHANGE
ID: lvchange_rebuild
DESC: Reconstruct data on specific PVs of a raid LV.
RULE: all not LV_raid0
# try removing the META change options from here?
lvchange --activate Active VG|LV|Tag|Select ...
OO: --activationmode ActivationMode, --partial, --ignoreactivationskip,
--ignorelockingfailure, --sysinit, OO_LVCHANGE_META, OO_LVCHANGE
OO: --activationmode ActivationMode, --partial, --ignoreactivationskip, OO_LVCHANGE_META, OO_LVCHANGE
ID: lvchange_activate
DESC: Activate or deactivate an LV.
@@ -291,18 +249,16 @@ lvchange --monitor Bool VG|LV|Tag|Select ...
OO: --poll Bool, OO_LVCHANGE
ID: lvchange_monitor
DESC: Start or stop monitoring an LV from dmeventd.
RULE: all not lv_is_pvmove
lvchange --poll Bool VG|LV|Tag|Select ...
OO: --monitor Bool, OO_LVCHANGE
ID: lvchange_poll
DESC: Start or stop processing an LV conversion.
lvchange --persistent y --minor Number LV
OO: --major Number, OO_LVCHANGE
lvchange --persistent Bool VG|LV|Tag|Select ...
OO: --minor Number, --major Number, OO_LVCHANGE
ID: lvchange_persistent
DESC: Make the minor device number persistent for an LV.
RULE: all not LV_thinpool LV_cachepool
---
@@ -312,72 +268,63 @@ OO_LVCONVERT_RAID: --mirrors SNumber, --stripes_long Number,
OO_LVCONVERT_POOL: --poolmetadata LV, --poolmetadatasize SizeMB,
--poolmetadataspare Bool, --readahead Readahead, --chunksize SizeKB
OO_LVCONVERT: --alloc Alloc, --background, --force, --noudevsync
OO_LVCONVERT: --alloc Alloc, --background, --force, --noudevsync,
--usepolicies
---
# These cover all the core, raid-related type conversions.
# They are all routed into the core raid conversion code.
# FIXME: lvconvert --merge is an extremely ambiguous command.
# It can do very different operations, but which one depends
# on knowing the LV type. So, the command doesn't know what
# it's actually doing until quite late, when processing a
# single LV.
#
# Use different option names for different merge operations
# so that we can have different command definitions,
# different behaviors, different optional options, etc:
#
# lvconvert --merge-mirror LV_linear_striped_raid ...
# DESC: Merge LV that was previously split from a mirror.
#
# lvconvert --merge-thin LV_thin
# DESC: Merge thin LV into its origin LV.
#
# lvconvert --merge-snapshot LV_snapshot
# DESC: Merge COW snapshot LV into its origin.
#
# Then we could add VG|Tag to --merge-mirror arg pos 1, because
# "lvconvert --merge VG|Tag" is a terrible command. It will do
# different operations on each LV it finds, depending on the
# current LV type.
lvconvert --type linear LV
OO: OO_LVCONVERT_RAID, OO_LVCONVERT
OP: PV ...
ID: lvconvert_raid_types
DESC: Convert LV to linear.
RULE: all not lv_is_locked lv_is_pvmove
lvconvert --type striped LV
OO: OO_LVCONVERT_RAID, OO_LVCONVERT
OP: PV ...
ID: lvconvert_raid_types
DESC: Convert LV to striped.
lvconvert --type mirror LV
OO: OO_LVCONVERT_RAID, OO_LVCONVERT, --mirrorlog MirrorLog
OP: PV ...
ID: lvconvert_raid_types
DESC: Convert LV to type mirror (also see type raid1).
lvconvert --type raid LV
OO: OO_LVCONVERT_RAID, OO_LVCONVERT
OP: PV ...
ID: lvconvert_raid_types
DESC: Convert LV to raid.
lvconvert --mirrors SNumber LV
OO: OO_LVCONVERT_RAID, OO_LVCONVERT, --mirrorlog MirrorLog
OP: PV ...
ID: lvconvert_raid_types
DESC: Convert LV to raid1 or mirror, or change number of mirror images.
lvconvert --merge LV_linear_striped_raid_thin_snapshot|VG|Tag ...
OO: --background, --interval Number, OO_LVCONVERT
ID: lvconvert_merge
DESC: Merge LV that was previously split from a mirror.
DESC: Merge thin LV into its origin LV.
DESC: Merge COW snapshot LV into its origin.
---
# lvconvert raid-related utilities
# Create a new command set for these and migrate them out of lvconvert?
# FIXME: by using two different positional args, this is the
# single violation of the standard method of using process_each_lv().
# Before calling process_each, it steals the first positional arg
# and adjusts argv/argc so it's not seen by process_each.
lvconvert --splitmirrors Number --name LV_new LV_raid1_mirror_cache
OO: OO_LVCONVERT
OP: PV ...
ID: lvconvert_split_mirror_images
DESC: Split images from a raid1 or mirror LV and use them to create a new LV.
# alternate form of lvconvert --snapshot
lvconvert --type snapshot LV_linear_striped_raid LV_snapshot
OO: --snapshot, --chunksize SizeKB, --zero Bool, OO_LVCONVERT
ID: lvconvert_combine_split_snapshot
DESC: Combine LV with a previously split snapshot LV.
FLAGS: SECONDARY_SYNTAX
lvconvert --splitmirrors Number --trackchanges LV_raid1_cache
OO: OO_LVCONVERT
OP: PV ...
ID: lvconvert_split_mirror_images
DESC: Split images from a raid1 LV and track changes to origin.
lvconvert --mirrorlog MirrorLog LV_mirror
OO: OO_LVCONVERT
OP: PV ...
ID: lvconvert_change_mirrorlog
DESC: Change the type of mirror log used by a mirror LV.
lvconvert --snapshot LV_linear_striped_raid LV_snapshot
OO: --type snapshot, --chunksize SizeKB, --zero Bool, OO_LVCONVERT
ID: lvconvert_combine_split_snapshot
DESC: Combine LV with a previously split snapshot LV.
---
# lvconvert utilities for creating/maintaining thin and cache objects.
# Create a new command set for these and migrate them out of lvconvert?
lvconvert --type thin --thinpool LV LV_linear_striped_raid
OO: --thin, --originname LV_new, --zero Bool, OO_LVCONVERT_POOL, OO_LVCONVERT
ID: lvconvert_to_thin_with_external
@@ -412,7 +359,6 @@ FLAGS: SECONDARY_SYNTAX
lvconvert --type thin-pool LV_linear_striped_raid_cache
OO: --stripes_long Number, --stripesize SizeKB,
--discards Discards, --zero Bool, OO_LVCONVERT_POOL, OO_LVCONVERT
OP: PV ...
ID: lvconvert_to_thinpool
DESC: Convert LV to type thin-pool.
@@ -421,7 +367,6 @@ DESC: Convert LV to type thin-pool.
lvconvert --thinpool LV_linear_striped_raid_cache
OO: --type thin-pool, --stripes_long Number, --stripesize SizeKB,
--discards Discards, --zero Bool, OO_LVCONVERT_POOL, OO_LVCONVERT
OP: PV ...
ID: lvconvert_to_thinpool
DESC: Convert LV to type thin-pool (variant, use --type thin-pool).
FLAGS: SECONDARY_SYNTAX
@@ -431,7 +376,6 @@ FLAGS: SECONDARY_SYNTAX
lvconvert --type cache-pool LV_linear_striped_raid
OO: OO_LVCONVERT_POOL, OO_LVCONVERT,
--cachemode CacheMode, --cachepolicy String, --cachesettings String
OP: PV ...
ID: lvconvert_to_cachepool
DESC: Convert LV to type cache-pool.
@@ -446,88 +390,109 @@ FLAGS: SECONDARY_SYNTAX
---
lvconvert --splitcache LV_cachepool_cache_thinpool
OO: OO_LVCONVERT
ID: lvconvert_split_and_keep_cachepool
DESC: Separate and keep the cache pool from a cache LV.
# FIXME: we should be able to remove LV_mirror from the list of accepted
# LV types, but there are some dubious commands in the test suite that
# fail without it (the tests should be cleaned up to avoid using commands
# that don't make sense.)
#
# FIXME: it would be nice to remove LV_raid1 from the list of accepted
# LV types and let raid1 be covered by just the second definition, but
# unfortunatley lvconvert --type mirror --mirrors N LV_raid1 will
# match the first definition since the LV type cannot be used when
# choosing a matching command definition.
lvconvert --type mirror --mirrors SNumber LV_linear_striped_raid1_mirror
OO: --mirrorlog MirrorLog, OO_LVCONVERT_RAID, OO_LVCONVERT
OP: PV ...
ID: lvconvert_to_mirror
DESC: Convert LV to type mirror.
lvconvert --type mirror LV_raid1
OO: --mirrors SNumber, OO_LVCONVERT_RAID, OO_LVCONVERT
OP: PV ...
ID: lvconvert_to_mirror
DESC: Convert LV from type raid1 to type mirror.
---
lvconvert --uncache LV_cache_thinpool
OO: OO_LVCONVERT
ID: lvconvert_split_and_delete_cachepool
DESC: Separate and delete the cache pool from a cache LV.
lvconvert --type raid LV_linear_striped_mirror_raid
OO: OO_LVCONVERT_RAID, OO_LVCONVERT
OP: PV ...
ID: lvconvert_to_raid
DESC: Convert LV to type raid.
DESC: Change LV between raid types.
---
# FIXME: add a new option defining this operation, e.g. --swapmetadata
# FIXME: there are two unique operations here that differ
# by only the LV type, so they have to be defined together.
# We don't know what this command is going to do until after
# the LV is read. It would be better if the alternate form
# variant were dropped to remove the ambiguity
# (then --type raid1|mirror would be required to change a
# linear or striped LV to raid1|mirror.)
#
# First command definition
# this changes the number of mirror images in a raid1|mirror LV.
# lvconvert --mirrors SNumber LV_raid_mirror
# ID: lvconvert_change_mirror_images
# DESC: Change the number of mirror images in the LV.
#
# Second command definition
# alternate form of: lvconvert --type raid1|mirror LV_linear_striped
# lvconvert --mirrors SNumber LV_linear_striped
# ID: lvconvert_to_raid1_or_mirror
# DESC: Convert LV to type raid1 or mirror
# DESC: (variant, infers --type raid1|mirror).
lvconvert --poolmetadata LV LV_thinpool_cachepool
# first def is unique, second def is alternate form of lvconvert --type raid1|mirror
lvconvert --mirrors SNumber LV_raid_mirror_linear_striped
OO: --type raid1, --type mirror, --mirrorlog MirrorLog, OO_LVCONVERT_RAID, OO_LVCONVERT
OP: PV ...
ID: lvconvert_to_mirrored_or_change_image_count
DESC: Change the number of mirror images in a raid1 or mirror LV.
DESC: Convert a linear or striped LV to type raid1 or mirror
DESC: (variant, infers --type raid1|mirror).
---
lvconvert --type striped LV_raid
OO: OO_LVCONVERT_RAID, OO_LVCONVERT
OP: PV ...
ID: lvconvert_raid_to_striped
DESC: Convert LV to type striped.
---
lvconvert --type linear LV_raid_mirror
OO: OO_LVCONVERT
ID: lvconvert_swap_pool_metadata
DESC: Swap metadata LV in a thin pool or cache pool (temporary command).
ID: lvconvert_raid_or_mirror_to_linear
DESC: Convert LV to type linear.
# FIXME: the 'mirrors 0' trick as an alias for linear
# is used inconsistently, confusing things and making
# definitions difficult.
# alternate form of lvconvert --type linear
lvconvert --mirrors 0 LV_raid_mirror
OO: --type linear, --type mirror, OO_LVCONVERT
ID: lvconvert_raid_or_mirror_to_linear
DESC: Convert LV to type linear (variant, infers --type linear).
FLAGS: SECONDARY_SYNTAX
---
# lvconvert utilities related to snapshots and repair.
# Create a new command set for these and migrate them out of lvconvert?
lvconvert --splitmirrors Number --name LV_new LV_raid1_mirror_cache
OO: OO_LVCONVERT
OP: PV ...
ID: lvconvert_split_mirror_images_to_new
DESC: Split images from a raid1 or mirror LV and use them to create a new LV.
# FIXME: lvconvert --merge is an extremely ambiguous command.
# It can do very different operations, but which one depends
# on knowing the LV type. So, the command doesn't know what
# it's actually doing until quite late, when processing a
# single LV.
#
# Use different option names for different merge operations
# so that we can have different command definitions,
# different behaviors, different optional options, etc:
#
# lvconvert --merge-mirror LV_linear_striped_raid ...
# DESC: Merge LV that was previously split from a mirror.
#
# lvconvert --merge-thin LV_thin
# DESC: Merge thin LV into its origin LV.
#
# lvconvert --merge-snapshot LV_snapshot
# DESC: Merge COW snapshot LV into its origin.
#
# Then we could add VG|Tag to --merge-mirror arg pos 1, because
# "lvconvert --merge VG|Tag" is a terrible command. It will do
# different operations on each LV it finds, depending on the
# current LV type.
lvconvert --merge LV_linear_striped_raid_thin_snapshot|VG|Tag ...
OO: --background, --interval Number, OO_LVCONVERT
ID: lvconvert_merge
DESC: Merge LV that was previously split from a mirror.
DESC: Merge thin LV into its origin LV.
DESC: Merge COW snapshot LV into its origin.
RULE: all not lv_is_merging_origin lv_is_virtual_origin lv_is_external_origin lv_is_merging_cow
lvconvert --mergesnapshot LV_snapshot ...
OO: --background, --interval Number, OO_LVCONVERT
ID: lvconvert_merge_snapshot
DESC: Merge LV that was previously split from a mirror.
RULE: all not lv_is_merging_origin lv_is_virtual_origin lv_is_external_origin lv_is_merging_cow
---
# NB: an unsual use of position args here, where
# the second position LV is the only one processed
# by process_each_lv.
# alternate form of lvconvert --snapshot
lvconvert --type snapshot LV_linear_striped_raid LV_snapshot
OO: --snapshot, --chunksize SizeKB, --zero Bool, OO_LVCONVERT
ID: lvconvert_combine_split_snapshot
DESC: Combine LV with a previously split snapshot LV.
FLAGS: SECONDARY_SYNTAX
lvconvert --snapshot LV_linear_striped_raid LV_snapshot
OO: --type snapshot, --chunksize SizeKB, --zero Bool, OO_LVCONVERT
ID: lvconvert_combine_split_snapshot
DESC: Combine LV with a previously split snapshot LV.
lvconvert --splitmirrors Number --trackchanges LV_raid1_cache
OO: OO_LVCONVERT
OP: PV ...
ID: lvconvert_split_mirror_images_and_track
DESC: Split images from a raid1 LV and track changes to origin.
---
@@ -546,8 +511,7 @@ DESC: Combine LV with a previously split snapshot LV.
# and the LV type is known.
lvconvert --repair LV_raid_mirror_thinpool
OO: --usepolicies, --interval Number, OO_LVCONVERT
OP: PV ...
OO: OO_LVCONVERT
ID: lvconvert_repair_pvs_or_thinpool
DESC: Replace failed PVs in a raid or mirror LV.
DESC: Repair a thin pool.
@@ -562,11 +526,32 @@ DESC: Replace specific PV(s) in a raid* LV with another PV.
---
lvconvert --mirrorlog MirrorLog LV_mirror
OO: OO_LVCONVERT
OP: PV ...
ID: lvconvert_change_mirrorlog
DESC: Change the type of mirror log used by a mirror LV.
---
lvconvert --splitcache LV_cachepool_cache_thinpool
OO: OO_LVCONVERT
ID: lvconvert_split_and_keep_cachepool
DESC: Separate and keep the cache pool from a cache LV.
---
lvconvert --uncache LV_cache_thinpool
OO: OO_LVCONVERT
ID: lvconvert_split_and_delete_cachepool
DESC: Separate and delete the cache pool from a cache LV.
---
lvconvert --splitsnapshot LV_snapshot
OO: OO_LVCONVERT
ID: lvconvert_split_cow_snapshot
DESC: Separate a COW snapshot from its origin LV.
RULE: all not lv_is_origin lv_is_external_origin lv_is_merging_cow lv_is_vg_writable lv_is_pvmove
---
@@ -575,12 +560,22 @@ RULE: all not lv_is_origin lv_is_external_origin lv_is_merging_cow lv_is_vg_writ
lvconvert LV_mirror
OO: OO_LVCONVERT
ID: lvconvert_poll_start
ID: lvconvert_poll_mirror
DESC: Poll mirror LV to collapse resync layers.
FLAGS: SECONDARY_SYNTAX
---
# FIXME: add a new option defining this operation, e.g. --swapmetadata
lvconvert --poolmetadata LV LV_thinpool_cachepool
OO: OO_LVCONVERT
ID: lvconvert_swap_pool_metadata
DESC: Swap metadata LV in a thin pool or cache pool (temporary command).
FLAGS: SECONDARY_SYNTAX
---
# --extents is not specified; it's an automatic alternative for --size
OO_LVCREATE: --addtag Tag, --alloc Alloc, --autobackup Bool, --activate Active,
@@ -1052,7 +1047,6 @@ lvextend --usepolicies LV_thinpool_snapshot
OO: --alloc Alloc, --autobackup Bool, --force, --mirrors SNumber,
--nofsck, --nosync, --noudevsync,
--reportformat ReportFmt, --resizefs
OP: PV ...
ID: lvextend_by_policy
DESC: Extend an LV according to a predefined policy.
@@ -1060,7 +1054,6 @@ DESC: Extend an LV according to a predefined policy.
lvmconfig
OO: OO_CONFIG
OP: String ...
ID: lvmconfig_general
---
@@ -1124,15 +1117,9 @@ ID: lvs_general
lvscan
OO: --all, --blockdevice, --ignorelockingfailure, --partial,
--readonly, --reportformat ReportFmt
--readonly, --reportformat ReportFmt, --cache_long
ID: lvscan_general
lvscan --cache_long
OO: --blockdevice, --ignorelockingfailure, --partial,
--readonly, --reportformat ReportFmt
OP: LV ...
ID: lvscan_cache
---
# None of these can function as a required option for pvchange.
@@ -1199,7 +1186,7 @@ ID: pvmove_one
DESC: Move PV extents.
pvmove
OO: --abort, --background, --interval Number
OO: --abort, --background
ID: pvmove_any
DESC: Continue or abort existing pvmove operations.
@@ -1226,7 +1213,7 @@ DESC: Display PV information.
pvscan --cache_long
OO: --ignorelockingfailure, --reportformat ReportFmt, --background,
--activate Active, --major Number, --minor Number
--activate Active, --major Number, --minor Number,
OP: PV|String ...
ID: pvscan_cache
DESC: Populate the lvmetad cache by scanning PVs.
@@ -1241,32 +1228,12 @@ ID: vgcfgbackup_general
---
OO_VGCFGRESTORE: --force_long, --metadatatype MetadataType
vgcfgrestore VG
OO: OO_VGCFGRESTORE
OO: --file String, --force_long, --list, --metadatatype MetadataType
ID: vgcfgrestore_by_vg
DESC: Restore VG metadata from last backup.
vgcfgrestore --file String VG
OO: OO_VGCFGRESTORE
ID: vgcfgrestore_by_file
DESC: Restore VG metadata from specified file.
vgcfgrestore --list VG
OO: OO_VGCFGRESTORE
ID: vgcfgrestore_list_by_vg
DESC: List all VG metadata backups.
# FIXME: the optional VG pos arg is not used or checked and can be
# anything, but a test in the test suite uses it. Fix the test or
# verify that the positional VG is correct?
vgcfgrestore --list --file String
OO: OO_VGCFGRESTORE
OP: VG
ID: vgcfgrestore_list_by_file
DESC: List one VG metadata backup file.
ID: vgcfgrestore_by_file
---
@@ -1283,7 +1250,7 @@ OO_VGCHANGE_META: --addtag Tag, --deltag Tag,
--logicalvolume Number, --maxphysicalvolumes Number, --alloc Alloc, --uuid,
--clustered Bool, --pvmetadatacopies MetadataCopiesPV, --vgmetadatacopies MetadataCopiesVG,
--physicalextentsize SizeMB, --resizeable Bool, --systemid String, --locktype LockType,
--profile String, --detachprofile, --metadataprofile String
--profile String, --detachprofile, --metadataprofile String,
vgchange OO_VGCHANGE_META
OO: OO_VGCHANGE
@@ -1497,19 +1464,15 @@ DESC: Split a VG by PVs in a specified LV.
# built-in and deprecated commands
# use lvmconfig
config
OO: OO_CONFIG
OP: String ...
ID: lvmconfig_general
FLAGS: SECONDARY_SYNTAX
# use lvmconfig
dumpconfig
OO: OO_CONFIG
OP: String ...
ID: lvmconfig_general
FLAGS: SECONDARY_SYNTAX
devtypes
OO: --aligned, --binary, --nameprefixes, --noheadings,
@@ -1539,10 +1502,8 @@ ID: help_general
version
ID: version_general
# deprecated
pvdata
ID: pvdata_general
FLAGS: SECONDARY_SYNTAX
segtypes
ID: segtypes_general
@@ -1553,25 +1514,17 @@ ID: systemid_general
tags
ID: tags_general
# deprecated
lvmchange
ID: lvmchange_general
FLAGS: SECONDARY_SYNTAX
# deprecated
lvmdiskscan
OO: --lvmpartition, --readonly
ID: lvmdiskscan_general
FLAGS: SECONDARY_SYNTAX
# deprecated
lvmsadc
ID: lvmsadc_general
FLAGS: SECONDARY_SYNTAX
# deprecated
lvmsar
OO: --full, --stdin
ID: lvmsar_general
FLAGS: SECONDARY_SYNTAX

View File

@@ -54,6 +54,27 @@ struct command_name {
#define ARG_DEF_FLAG_NEW 1 << 0
#define ARG_DEF_FLAG_MAY_REPEAT 1 << 1
/* arg_def lv_types */
enum {
ARG_DEF_LV_ANY = 0,
ARG_DEF_LV_LINEAR = 1 << 0,
ARG_DEF_LV_STRIPED = 1 << 1,
ARG_DEF_LV_SNAPSHOT = 1 << 2,
ARG_DEF_LV_MIRROR = 1 << 3,
ARG_DEF_LV_RAID = 1 << 4,
ARG_DEF_LV_RAID0 = 1 << 5,
ARG_DEF_LV_RAID1 = 1 << 6,
ARG_DEF_LV_RAID4 = 1 << 7,
ARG_DEF_LV_RAID5 = 1 << 8,
ARG_DEF_LV_RAID6 = 1 << 9,
ARG_DEF_LV_RAID10 = 1 << 10,
ARG_DEF_LV_THIN = 1 << 11,
ARG_DEF_LV_THINPOOL = 1 << 12,
ARG_DEF_LV_CACHE = 1 << 13,
ARG_DEF_LV_CACHEPOOL = 1 << 14,
ARG_DEF_LV_LAST = 1 << 15,
};
static inline int val_bit_is_set(uint64_t val_bits, int val_enum)
{
return (val_bits & (1 << val_enum)) ? 1 : 0;
@@ -64,33 +85,13 @@ 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 lv_types; /* ARG_DEF_LV_, for lv_VAL, can be multiple */
uint32_t flags; /* ARG_DEF_FLAG_ */
};
@@ -108,33 +109,6 @@ struct pos_arg {
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
@@ -144,7 +118,6 @@ struct cmd_rule {
#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_MAX_RULES 32 /* max number of rules per command def */
/*
* one or more from required_opt_args is required,
@@ -185,8 +158,6 @@ struct command {
/* optional positional args */
struct pos_arg optional_pos_args[CMD_OP_ARGS];
struct cmd_rule rules[CMD_MAX_RULES];
int ro_count;
int oo_count;
int rp_count;
@@ -194,8 +165,6 @@ struct command {
/* used for processing current position */
int pos_count;
int rule_count;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1611,7 +1611,7 @@ static int _udevcomplete_all(CMD_ARGS)
}
if (!_switches[YES_ARG]) {
log_warn("WARNING: This operation will destroy all semaphores %s%.0d%swith keys "
log_warn("This operation will destroy all semaphores %s%.0d%swith keys "
"that have a prefix %" PRIu16 " (0x%" PRIx16 ").",
age ? "older than " : "", age, age ? " minutes " : "",
DM_COOKIE_MAGIC, DM_COOKIE_MAGIC);
@@ -2707,9 +2707,6 @@ static int _add_dep(CMD_ARGS)
/*
* Create and walk dependency tree
*
* An incomplete _dtree may still be used by the caller,
* but the error must be reported.
*/
static int _build_whole_deptree(const struct command *cmd)
{
@@ -2727,14 +2724,12 @@ static int _build_whole_deptree(const struct command *cmd)
static int _display_tree(CMD_ARGS)
{
int r;
if (!_build_whole_deptree(cmd))
return_0;
r = _build_whole_deptree(cmd);
_display_tree_walk_children(dm_tree_find_node(_dtree, 0, 0), 0);
if (_dtree)
_display_tree_walk_children(dm_tree_find_node(_dtree, 0, 0), 0);
return r;
return 1;
}
/*
@@ -4476,14 +4471,9 @@ static int _report_init(const struct command *cmd, const char *subcommand)
selection, NULL, NULL)))
goto_out;
r = 1;
if ((_report_type & DR_TREE) && cmd) {
r = _build_whole_deptree(cmd);
if (!_dtree) {
err("Internal device dependency tree creation failed.");
goto out;
}
if ((_report_type & DR_TREE) && cmd && !_build_whole_deptree(cmd)) {
err("Internal device dependency tree creation failed.");
goto out;
}
if (!_switches[INTERVAL_ARG])
@@ -4494,6 +4484,8 @@ static int _report_init(const struct command *cmd, const char *subcommand)
if (field_prefixes)
dm_report_set_output_field_name_prefix(_report, "dm_");
r = 1;
out:
if (len)
dm_free(options);
@@ -5278,8 +5270,6 @@ static int _stats_delete(CMD_ARGS)
name = argv[0];
}
if (_switches[PROGRAM_ID_ARG])
program_id = _string_args[PROGRAM_ID_ARG];
if (_switches[ALL_PROGRAMS_ARG])
program_id = DM_STATS_ALL_PROGRAMS;
@@ -5323,7 +5313,7 @@ static int _stats_delete(CMD_ARGS)
log_error("Could not delete statistics region");
goto out;
}
log_info("Deleted statistics region " FMTu64 ".", region_id);
log_info("Deleted statistics region " FMTu64 ".\n", region_id);
}
r = 1;
@@ -6792,15 +6782,8 @@ unknown:
argc--, argv++;
}
/* Default to success */
ret = 0;
if (_switches[COLS_ARG]) {
if (!_report_init(cmd, subcommand))
ret = 1;
if (ret || !_report)
goto_out;
}
if (_switches[COLS_ARG] && !_report_init(cmd, subcommand))
goto_out;
if (_switches[COUNT_ARG])
_count = ((uint32_t)_int_args[COUNT_ARG]) ? : UINT32_MAX;
@@ -6812,17 +6795,14 @@ unknown:
&_disp_units);
if (!_disp_factor) {
log_error("Invalid --units argument.");
ret = 1;
goto out;
}
}
/* Start interval timer. */
if (_count > 1)
if (!_start_timer()) {
ret = 1;
if (!_start_timer())
goto_out;
}
doit:
multiple_devices = (cmd->repeatable_cmd && argc != 1 &&
@@ -6839,19 +6819,18 @@ doit:
if (_count > 1 && r) {
printf("\n");
/* wait for --interval and update timestamps */
if (!_do_report_wait()) {
ret = 1;
if (!_do_report_wait())
goto_out;
}
}
}
if (!r) {
ret = 1;
if (!r)
goto_out;
}
} while (--_count);
/* Success */
ret = 0;
out:
if (_report)
dm_report_free(_report);
@@ -6864,5 +6843,5 @@ out:
if (_initial_timestamp)
dm_timestamp_destroy(_initial_timestamp);
return (_switches[HELP_ARG] || _switches[VERSION_ARG]) ? 0 : ret;
return ret;
}

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,32 +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(LVT_COUNT, "", NULL)

View File

@@ -25,6 +25,12 @@ static int _lvchange_permission(struct cmd_context *cmd,
lv_access = arg_uint_value(cmd, permission_ARG, 0);
if (lv_is_external_origin(lv)) {
log_error("Cannot change permissions of external origin %s.",
display_lvname(lv));
return 0;
}
if (!(lv_access & LVM_WRITE) && !(lv->status & LVM_WRITE)) {
/* Refresh if it's read-only in metadata but read-write in kernel */
if (lv_info(cmd, lv, 0, &info, 0, 0) && info.exists && !info.read_only) {
@@ -57,6 +63,20 @@ static int _lvchange_permission(struct cmd_context *cmd,
return 0;
}
/* Not allowed to change permissions on RAID sub-LVs directly */
if (lv_is_raid_metadata(lv) || lv_is_raid_image(lv)) {
log_error("Cannot change permissions of RAID %s %s.",
lv_is_raid_image(lv) ? "image" : "metadata area",
display_lvname(lv));
return 0;
}
if (!(lv_access & LVM_WRITE) && lv_is_thin_pool(lv)) {
log_error("Change permissions of thin pool %s not yet supported.",
display_lvname(lv));
return 0;
}
if (lv_access & LVM_WRITE) {
lv->status |= LVM_WRITE;
log_verbose("Setting logical volume %s read/write.",
@@ -80,6 +100,12 @@ static int _lvchange_pool_update(struct cmd_context *cmd,
unsigned val;
thin_discards_t discards;
if (!lv_is_thin_pool(lv)) {
log_error("Logical volume %s is not a thin pool.",
display_lvname(lv));
return 0;
}
if (arg_is_set(cmd, discards_ARG)) {
discards = (thin_discards_t) arg_uint_value(cmd, discards_ARG, THIN_DISCARDS_IGNORE);
if (discards != first_seg(lv)->discards) {
@@ -127,6 +153,10 @@ static int _lvchange_monitoring(struct cmd_context *cmd,
return 0;
}
/* do not monitor pvmove lv's */
if (lv_is_pvmove(lv))
return 1;
if ((dmeventd_monitor_mode() != DMEVENTD_MONITOR_IGNORE) &&
!monitor_dev_for_events(cmd, lv, 0, dmeventd_monitor_mode()))
return_0;
@@ -250,6 +280,20 @@ static int attach_metadata_devices(struct lv_segment *seg, struct dm_list *list)
return 1;
}
/*
* lvchange_refresh
* @cmd
* @lv
*
* Suspend and resume a logical volume.
*/
static int _lvchange_refresh(struct cmd_context *cmd, struct logical_volume *lv)
{
log_verbose("Refreshing logical volume %s (if active).", display_lvname(lv));
return lv_refresh(cmd, lv);
}
static int _reactivate_lv(struct logical_volume *lv,
int active, int exclusive)
{
@@ -282,6 +326,23 @@ static int _lvchange_resync(struct cmd_context *cmd, struct logical_volume *lv)
dm_list_init(&device_list);
if (seg_is_any_raid0(seg) ||
(!seg_is_mirror(seg) && !seg_is_raid(seg))) {
log_error("Unable to resync %s. It is not RAID4/5/6/10 or mirrored.",
display_lvname(lv));
return 0;
}
if (lv_is_pvmove(lv)) {
log_error("Unable to resync pvmove volume %s.", display_lvname(lv));
return 0;
}
if (lv_is_locked(lv)) {
log_error("Unable to resync locked volume %s.", display_lvname(lv));
return 0;
}
if (lv_is_active_locally(lv)) {
if (!lv_check_not_in_use(lv, 1)) {
log_error("Can't resync open logical volume %s.",
@@ -630,6 +691,15 @@ static int _lvchange_cache(struct cmd_context *cmd, struct logical_volume *lv)
if (lv_is_cache(lv))
pool_seg = first_seg(pool_seg->pool_lv);
else if (!lv_is_cache_pool(lv)) {
log_error("LV %s is not a cache LV.", display_lvname(lv));
(void) arg_from_list_is_set(cmd, "is supported only with cache or cache pool LVs",
cachemode_ARG,
cachepolicy_ARG,
cachesettings_ARG,
-1);
goto out;
}
if (!get_cache_params(cmd, &mode, &name, &settings))
goto_out;
@@ -689,6 +759,12 @@ static int _lvchange_rebuild(struct logical_volume *lv)
struct arg_value_group_list *group;
struct volume_group *vg = lv->vg;
struct cmd_context *cmd = vg->cmd;
struct lv_segment *raid_seg = first_seg(lv);
if (!seg_is_raid(raid_seg) || seg_is_any_raid0(raid_seg)) {
log_error("--rebuild can only be used with 'raid4/5/6/10' segment types.");
return 0;
}
if (!(pv_count = arg_count(cmd, rebuild_ARG))) {
log_error("No --rebuild found!");
@@ -739,6 +815,12 @@ static int _lvchange_writemostly(struct logical_volume *lv)
struct cmd_context *cmd = lv->vg->cmd;
struct lv_segment *raid_seg = first_seg(lv);
if (!seg_is_raid1(raid_seg)) {
log_error("--write%s can only be used with 'raid1' segment type.",
arg_is_set(cmd, writemostly_ARG) ? "mostly" : "behind");
return 0;
}
if (arg_is_set(cmd, writebehind_ARG))
raid_seg->writebehind = arg_uint_value(cmd, writebehind_ARG, 0);
@@ -827,6 +909,12 @@ static int _lvchange_recovery_rate(struct logical_volume *lv)
struct cmd_context *cmd = lv->vg->cmd;
struct lv_segment *raid_seg = first_seg(lv);
if (!seg_is_raid(raid_seg)) {
log_error("Unable to change the recovery rate of non-RAID "
"logical volume %s.", display_lvname(lv));
return 0;
}
if (arg_is_set(cmd, minrecoveryrate_ARG))
raid_seg->min_recovery_rate =
arg_uint_value(cmd, minrecoveryrate_ARG, 0) / 2;
@@ -894,25 +982,522 @@ static int _lvchange_activation_skip(struct logical_volume *lv)
return 1;
}
static int _lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
struct processing_handle *handle __attribute__((unused)))
{
int doit = 0, docmds = 0;
struct logical_volume *origin;
char snaps_msg[128];
if (sigint_caught())
return_ECMD_FAILED;
if (!(lv->vg->status & LVM_WRITE) &&
arg_from_list_is_set(cmd, NULL,
alloc_ARG,
contiguous_ARG,
discards_ARG,
metadataprofile_ARG,
permission_ARG,
persistent_ARG,
profile_ARG,
readahead_ARG,
zero_ARG,
-1)) {
log_error("Only -a permitted with read-only volume group %s.",
lv->vg->name);
return ECMD_FAILED;
}
if (lv_is_origin(lv) && !lv_is_thin_volume(lv) &&
arg_from_list_is_set(cmd, NULL,
alloc_ARG,
contiguous_ARG,
metadataprofile_ARG,
permission_ARG,
persistent_ARG,
profile_ARG,
readahead_ARG,
-1)) {
log_error("Can't change logical volume %s under snapshot.",
display_lvname(lv));
return ECMD_FAILED;
}
if (lv_is_pvmove(lv)) {
log_error("Unable to change pvmove LV %s.", display_lvname(lv));
if (arg_is_set(cmd, activate_ARG))
log_error("Use 'pvmove --abort' to abandon a pvmove");
return ECMD_FAILED;
}
if (lv_is_mirror_log(lv)) {
log_error("Unable to change mirror log LV %s directly.",
display_lvname(lv));
return ECMD_FAILED;
}
if (lv_is_mirror_image(lv)) {
log_error("Unable to change mirror image LV %s directly.",
display_lvname(lv));
return ECMD_FAILED;
}
/* If LV is sparse, activate origin instead */
if (arg_is_set(cmd, activate_ARG) && lv_is_cow(lv) &&
lv_is_virtual_origin(origin = origin_from_cow(lv)))
lv = origin;
/* Use cache origin LV for 'raid' actions */
if (lv_is_cache(lv) &&
arg_from_list_is_set(cmd, NULL,
/* FIXME: we want to support more ops here */
//resync_ARG,
syncaction_ARG,
-1)) {
lv = seg_lv(first_seg(lv), 0);
log_debug("Using cache origin volume %s for lvchange instead.",
display_lvname(lv));
}
if ((lv_is_thin_pool_data(lv) || lv_is_thin_pool_metadata(lv) ||
lv_is_cache_pool_data(lv) || lv_is_cache_pool_metadata(lv)) &&
!arg_is_set(cmd, activate_ARG) &&
!arg_is_set(cmd, permission_ARG) &&
!arg_is_set(cmd, setactivationskip_ARG))
/* Rest can be changed for stacked thin pool meta/data volumes */
;
else if (lv_is_cache_origin(lv) && lv_is_raid(lv)) {
if (vg_is_clustered(lv->vg)) {
log_error("Unable to change internal LV %s directly in a cluster.",
display_lvname(lv));
return ECMD_FAILED;
}
/*
* FIXME: For now, we don't want to allow all kinds of
* operations on this cache origin sub-LV. We are going
* to restrict it to non-clustered, RAID. This way, we
* can change the syncaction as needed (e.g. initiate
* scrubbing).
*
* Later pass all 'cache' actions on cache origin.
*/
} else if (!lv_is_visible(lv) && !lv_is_virtual_origin(lv)) {
log_error("Unable to change internal LV %s directly.",
display_lvname(lv));
return ECMD_FAILED;
}
if (lv_is_cow(lv) && arg_is_set(cmd, activate_ARG)) {
origin = origin_from_cow(lv);
if (origin->origin_count < 2)
snaps_msg[0] = '\0';
else if (dm_snprintf(snaps_msg, sizeof(snaps_msg),
" and %u other snapshot(s)",
origin->origin_count - 1) < 0) {
log_error("Failed to prepare message.");
return ECMD_FAILED;
}
if (!arg_is_set(cmd, yes_ARG) &&
(yes_no_prompt("Change of snapshot %s will also change its "
"origin %s%s. Proceed? [y/n]: ",
display_lvname(lv), display_lvname(origin),
snaps_msg) == 'n')) {
log_error("Logical volume %s not changed.", display_lvname(lv));
return ECMD_FAILED;
}
}
if (arg_is_set(cmd, errorwhenfull_ARG) && !lv_is_thin_pool(lv)) {
log_error("Option --errorwhenfull is only supported with thin pools.");
return ECMD_FAILED;
}
if (arg_is_set(cmd, persistent_ARG) && lv_is_pool(lv)) {
log_error("Persistent major and minor numbers are not supported with pools.");
return ECMD_FAILED;
}
if (!arg_is_set(cmd, activate_ARG) && !arg_is_set(cmd, refresh_ARG)) {
/*
* If a persistent lv lock already exists from activation
* (with the needed mode or higher), this will be a no-op.
* Otherwise, the lv lock will be taken as non-persistent
* and released when this command exits.
*
* FIXME: use "sh" if the options imply that the lvchange
* operation does not modify the LV.
*/
if (!lockd_lv(cmd, lv, "ex", 0)) {
stack;
return ECMD_FAILED;
}
}
/*
* FIXME: DEFAULT_BACKGROUND_POLLING should be "unspecified".
* If --poll is explicitly provided use it; otherwise polling
* should only be started if the LV is not already active. So:
* 1) change the activation code to say if the LV was actually activated
* 2) make polling of an LV tightly coupled with LV activation
*
* Do not initiate any polling if --sysinit option is used.
*/
init_background_polling(arg_is_set(cmd, sysinit_ARG) ? 0 :
arg_int_value(cmd, poll_ARG,
DEFAULT_BACKGROUND_POLLING));
/* access permission change */
if (arg_is_set(cmd, permission_ARG)) {
if (!archive(lv->vg))
return_ECMD_FAILED;
doit += _lvchange_permission(cmd, lv);
docmds++;
}
/* allocation policy change */
if (arg_is_set(cmd, contiguous_ARG) || arg_is_set(cmd, alloc_ARG)) {
if (!archive(lv->vg))
return_ECMD_FAILED;
doit += _lvchange_alloc(cmd, lv);
docmds++;
}
/* error when full change */
if (arg_is_set(cmd, errorwhenfull_ARG)) {
if (!archive(lv->vg))
return_ECMD_FAILED;
doit += _lvchange_errorwhenfull(cmd, lv);
docmds++;
}
/* read ahead sector change */
if (arg_is_set(cmd, readahead_ARG)) {
if (!archive(lv->vg))
return_ECMD_FAILED;
doit += _lvchange_readahead(cmd, lv);
docmds++;
}
/* persistent device number change */
if (arg_is_set(cmd, persistent_ARG)) {
if (!archive(lv->vg))
return_ECMD_FAILED;
doit += _lvchange_persistent(cmd, lv);
docmds++;
}
if (arg_is_set(cmd, discards_ARG) ||
arg_is_set(cmd, zero_ARG)) {
if (!archive(lv->vg))
return_ECMD_FAILED;
doit += _lvchange_pool_update(cmd, lv);
docmds++;
}
/* add tag */
if (arg_is_set(cmd, addtag_ARG)) {
if (!archive(lv->vg))
return_ECMD_FAILED;
doit += _lvchange_tag(cmd, lv, addtag_ARG);
docmds++;
}
/* del tag */
if (arg_is_set(cmd, deltag_ARG)) {
if (!archive(lv->vg))
return_ECMD_FAILED;
doit += _lvchange_tag(cmd, lv, deltag_ARG);
docmds++;
}
/* rebuild selected PVs */
if (arg_is_set(cmd, rebuild_ARG)) {
if (!archive(lv->vg))
return_ECMD_FAILED;
doit += _lvchange_rebuild(lv);
docmds++;
}
/* change writemostly/writebehind */
if (arg_is_set(cmd, writemostly_ARG) || arg_is_set(cmd, writebehind_ARG)) {
if (!archive(lv->vg))
return_ECMD_FAILED;
doit += _lvchange_writemostly(lv);
docmds++;
}
/* change [min|max]_recovery_rate */
if (arg_is_set(cmd, minrecoveryrate_ARG) ||
arg_is_set(cmd, maxrecoveryrate_ARG)) {
if (!archive(lv->vg))
return_ECMD_FAILED;
doit += _lvchange_recovery_rate(lv);
docmds++;
}
/* change configuration profile */
if (arg_is_set(cmd, profile_ARG) || arg_is_set(cmd, metadataprofile_ARG) ||
arg_is_set(cmd, detachprofile_ARG)) {
if (!archive(lv->vg))
return_ECMD_FAILED;
doit += _lvchange_profile(lv);
docmds++;
}
if (arg_is_set(cmd, setactivationskip_ARG)) {
if (!archive(lv->vg))
return_ECMD_FAILED;
doit += _lvchange_activation_skip(lv);
docmds++;
}
if (arg_is_set(cmd, cachemode_ARG) ||
arg_is_set(cmd, cachepolicy_ARG) || arg_is_set(cmd, cachesettings_ARG)) {
if (!archive(lv->vg))
return_ECMD_FAILED;
doit += _lvchange_cache(cmd, lv);
docmds++;
}
if (doit)
log_print_unless_silent("Logical volume %s changed.", display_lvname(lv));
if (arg_is_set(cmd, resync_ARG) &&
!_lvchange_resync(cmd, lv))
return_ECMD_FAILED;
if (arg_is_set(cmd, syncaction_ARG)) {
struct lv_segment *seg = first_seg(lv);
if (seg_is_any_raid0(seg)) {
log_error("Unable to sync raid0 LV %s.", display_lvname(lv));
return_ECMD_FAILED;
}
if (!lv_raid_message(lv, arg_str_value(cmd, syncaction_ARG, NULL)))
return_ECMD_FAILED;
}
/* activation change */
if (arg_is_set(cmd, activate_ARG)) {
if (!_lvchange_activate(cmd, lv))
return_ECMD_FAILED;
} else if (arg_is_set(cmd, refresh_ARG)) {
if (!_lvchange_refresh(cmd, lv))
return_ECMD_FAILED;
} else {
if (arg_is_set(cmd, monitor_ARG) &&
!_lvchange_monitoring(cmd, lv))
return_ECMD_FAILED;
if (arg_is_set(cmd, poll_ARG) &&
!_lvchange_background_polling(cmd, lv))
return_ECMD_FAILED;
}
if (doit != docmds)
return_ECMD_FAILED;
return ECMD_PROCESSED;
}
int lvchange(struct cmd_context *cmd, int argc, char **argv)
{
/*
* Options that update metadata should be listed in one of
* the two lists below (i.e. options other than -a, --refresh,
* --monitor or --poll).
*/
int update_partial_safe = /* options safe to update if partial */
arg_from_list_is_set(cmd, NULL,
addtag_ARG,
contiguous_ARG,
deltag_ARG,
detachprofile_ARG,
metadataprofile_ARG,
permission_ARG,
persistent_ARG,
profile_ARG,
readahead_ARG,
setactivationskip_ARG,
-1);
int update_partial_unsafe =
arg_from_list_is_set(cmd, NULL,
alloc_ARG,
cachemode_ARG,
cachepolicy_ARG,
cachesettings_ARG,
discards_ARG,
errorwhenfull_ARG,
maxrecoveryrate_ARG,
minrecoveryrate_ARG,
rebuild_ARG,
resync_ARG,
syncaction_ARG,
writebehind_ARG,
writemostly_ARG,
zero_ARG,
-1);
int update = update_partial_safe || update_partial_unsafe;
if (!update &&
!arg_is_set(cmd, activate_ARG) && !arg_is_set(cmd, refresh_ARG) &&
!arg_is_set(cmd, monitor_ARG) && !arg_is_set(cmd, poll_ARG)) {
log_error("Need 1 or more of -a, -C, -M, -p, -r, -Z, "
"--resync, --refresh, --alloc, --addtag, --deltag, "
"--monitor, --poll or --discards");
return EINVALID_CMD_LINE;
}
if ((arg_is_set(cmd, profile_ARG) || arg_is_set(cmd, metadataprofile_ARG)) &&
arg_is_set(cmd, detachprofile_ARG)) {
log_error("Only one of --metadataprofile and --detachprofile permitted.");
return EINVALID_CMD_LINE;
}
if (arg_is_set(cmd, activate_ARG) && arg_is_set(cmd, refresh_ARG)) {
log_error("Only one of -a and --refresh permitted.");
return EINVALID_CMD_LINE;
}
if ((arg_is_set(cmd, ignorelockingfailure_ARG) ||
arg_is_set(cmd, sysinit_ARG)) && update) {
log_error("Only -a permitted with --ignorelockingfailure and --sysinit");
return EINVALID_CMD_LINE;
}
if (!update || !update_partial_unsafe)
cmd->handles_missing_pvs = 1;
if (!argc && !arg_is_set(cmd, select_ARG)) {
log_error("Please give logical volume path(s) or use --select for selection.");
return EINVALID_CMD_LINE;
}
if ((arg_is_set(cmd, minor_ARG) || arg_is_set(cmd, major_ARG)) &&
!arg_is_set(cmd, persistent_ARG)) {
log_error("--major and --minor require -My.");
return EINVALID_CMD_LINE;
}
if (arg_is_set(cmd, minor_ARG) && argc != 1) {
log_error("Only give one logical volume when specifying minor.");
return EINVALID_CMD_LINE;
}
if (arg_is_set(cmd, contiguous_ARG) && arg_is_set(cmd, alloc_ARG)) {
log_error("Only one of --alloc and --contiguous permitted.");
return EINVALID_CMD_LINE;
}
if (arg_is_set(cmd, poll_ARG) && arg_is_set(cmd, sysinit_ARG)) {
log_error("Only one of --poll and --sysinit permitted.");
return EINVALID_CMD_LINE;
}
/*
* If --sysinit -aay is used and at the same time lvmetad is used,
* we want to rely on autoactivation to take place. Also, we
* need to take special care here as lvmetad service does
* not neet to be running at this moment yet - it could be
* just too early during system initialization time.
*/
if (arg_is_set(cmd, sysinit_ARG) && (arg_uint_value(cmd, activate_ARG, 0) == CHANGE_AAY)) {
if (lvmetad_used()) {
log_warn("WARNING: lvmetad is active, skipping direct activation during sysinit.");
return ECMD_PROCESSED;
}
}
/*
* Include foreign VGs that contain active LVs.
* That shouldn't happen in general, but if it does by some
* mistake, then we want to allow those LVs to be deactivated.
*/
if (arg_is_set(cmd, activate_ARG))
cmd->include_active_foreign_vgs = 1;
/*
* The default vg lock mode for lvchange is ex, but these options
* are cases where lvchange does not modify the vg, so they can use
* the sh lock mode.
*/
if (arg_is_set(cmd, activate_ARG) || arg_is_set(cmd, refresh_ARG)) {
cmd->lockd_vg_default_sh = 1;
/* Allow deactivating if locks fail. */
if (is_change_activating((activation_change_t)arg_uint_value(cmd, activate_ARG, CHANGE_AY)))
cmd->lockd_vg_enforce_sh = 1;
}
return process_each_lv(cmd, argc, argv, NULL, NULL,
update ? READ_FOR_UPDATE : 0, NULL,
&_lvchange_single);
}
#if 0
/*
* For each lvchange command definintion:
* Check if the status of the LV allows running lvchange.
*
* lvchange_foo_cmd(cmd, argc, argv);
* . set cmd fields that apply to "foo"
* . set any other things that affect behavior of process_each
* . process_each_lv(_lvchange_foo_single);
*
* _lvchange_foo_single(lv);
* . _lvchange_foo(lv);
* . (or all the code could live in the _single fn)
* FIXME: check for invalid VG/LV properties in a way that is not prone
* to missing some. Currently, there are some checks here, some in the
* functions above, some in process_each, and some may be missing.
*/
static int _lvchange_status_is_valid(struct cmd_context *cmd, struct logical_volume *lv)
{
if (!(lv->vg->status & LVM_WRITE)) {
log_error("Operation not permitted on LV %s: writable VG required.",
display_lvname(lv));
return 0;
}
if (lv_is_pvmove(lv)) {
log_error("Operation not permitted on LV %s: used for pvmove.",
display_lvname(lv));
if (arg_is_set(cmd, activate_ARG))
log_error("Use 'pvmove --abort' to abandon a pvmove");
return 0;
}
if (lv_is_mirror_log(lv)) {
log_error("Operation not permitted on LV %s: is mirror log.",
display_lvname(lv));
return 0;
}
if (lv_is_mirror_image(lv)) {
log_error("Operation not permitted on LV %s: is mirror image.",
display_lvname(lv));
return 0;
}
if (lv_is_origin(lv) && !lv_is_thin_volume(lv)) {
log_error("Operation not permitted on LV %s: is under snapshot.",
display_lvname(lv));
return 0;
}
return 1;
}
static int _lvchange_properties_single(struct cmd_context *cmd,
struct logical_volume *lv,
struct processing_handle *handle)
{
int doit = 0, docmds = 0;
int i, opt_enum;
/* FIXME: sort out hidden/internal LVs, e.g. _lvchange_hidden_is_valid() */
if (!_lvchange_status_is_valid(cmd, lv))
return_ECMD_FAILED;
if (arg_is_set(cmd, persistent_ARG) && lv_is_pool(lv)) {
log_error("Operation not permitted on LV %s: persistent device numbers are not supported with pools.",
display_lvname(lv));
return ECMD_FAILED;
}
/*
* If a persistent lv lock already exists from activation
@@ -997,7 +1582,6 @@ static int _lvchange_properties_single(struct cmd_context *cmd,
default:
log_error(INTERNAL_ERROR "Failed to check for option %s",
arg_long_option_name(i));
}
}
if (doit)
@@ -1011,12 +1595,13 @@ static int _lvchange_properties_single(struct cmd_context *cmd,
int lvchange_properties_cmd(struct cmd_context *cmd, int argc, char **argv)
{
/*
* A command def rule allows only some options when LV is partial,
* so handles_missing_pvs will only affect those.
*/
cmd->handles_missing_pvs = 1;
return process_each_lv(cmd, argc, argv, NULL, NULL, READ_FOR_UPDATE, NULL, _lvchange_properties_single);
struct processing_handle *handle = init_processing_handle(cmd, NULL);
int ret;
ret = process_each_lv(cmd, argc, argv, NULL, NULL, READ_FOR_UPDATE, handle, _lvchange_properties_single);
destroy_processing_handle(cmd, handle);
return ret;
}
static int _lvchange_activate_single(struct cmd_context *cmd,
@@ -1026,6 +1611,11 @@ static int _lvchange_activate_single(struct cmd_context *cmd,
struct logical_volume *origin;
char snaps_msg[128];
/* FIXME: sort out hidden/internal LVs, e.g. _lvchange_hidden_is_valid() */
if (!_lvchange_status_is_valid(cmd, lv))
return_ECMD_FAILED;
/* FIXME: untangle the proper logic for cow / sparse / virtual origin */
/* If LV is sparse, activate origin instead */
@@ -1075,6 +1665,8 @@ static int _lvchange_activate_single(struct cmd_context *cmd,
int lvchange_activate_cmd(struct cmd_context *cmd, int argc, char **argv)
{
struct processing_handle *handle = init_processing_handle(cmd, NULL);
cmd->handles_missing_pvs = 1;
cmd->lockd_vg_default_sh = 1;
@@ -1089,16 +1681,24 @@ int lvchange_activate_cmd(struct cmd_context *cmd, int argc, char **argv)
if (is_change_activating((activation_change_t)arg_uint_value(cmd, activate_ARG, CHANGE_AY)))
cmd->lockd_vg_enforce_sh = 1;
return process_each_lv(cmd, argc, argv, NULL, NULL, 0, NULL, _lvchange_activate_single);
ret = process_each_lv(cmd, argc, argv, NULL, NULL, 0, handle, _lvchange_activate_single);
destroy_processing_handle(cmd, handle);
return ret;
}
static int _lvchange_refresh_single(struct cmd_context *cmd,
struct logical_volume *lv,
struct processing_handle *handle)
{
/* FIXME: sort out hidden/internal LVs, e.g. _lvchange_hidden_is_valid() */
if (!_lvchange_status_is_valid(cmd, lv))
return_ECMD_FAILED;
log_verbose("Refreshing logical volume %s (if active).", display_lvname(lv));
if (!lv_refresh(cmd, lv))
if (!_lv_refresh(cmd, lv))
return_ECMD_FAILED;
return ECMD_PROCESSED;
@@ -1106,98 +1706,16 @@ static int _lvchange_refresh_single(struct cmd_context *cmd,
int lvchange_refresh_cmd(struct cmd_context *cmd, int argc, char **argv)
{
struct processing_handle *handle = init_processing_handle(cmd, NULL);
int ret;
cmd->handles_missing_pvs = 1;
cmd->lockd_vg_default_sh = 1;
return process_each_lv(cmd, argc, argv, NULL, NULL, 0, NULL, _lvchange_refresh_single);
}
static int _lvchange_resync_single(struct cmd_context *cmd,
struct logical_volume *lv,
struct processing_handle *handle)
{
if (!_lvchange_resync(cmd, lv))
return_ECMD_FAILED;
return ECMD_PROCESSED;
}
int lvchange_resync_cmd(struct cmd_context *cmd, int argc, char **argv)
{
return process_each_lv(cmd, argc, argv, NULL, NULL, READ_FOR_UPDATE, NULL, _lvchange_resync_single);
}
static int _lvchange_syncaction_single(struct cmd_context *cmd,
struct logical_volume *lv,
struct processing_handle *handle)
{
if (!lv_raid_message(lv, arg_str_value(cmd, syncaction_ARG, NULL)))
return_ECMD_FAILED;
return ECMD_PROCESSED;
}
int lvchange_syncaction_cmd(struct cmd_context *cmd, int argc, char **argv)
{
return process_each_lv(cmd, argc, argv, NULL, NULL, READ_FOR_UPDATE, NULL, _lvchange_syncaction_single);
}
static int _lvchange_rebuild_single(struct cmd_context *cmd,
struct logical_volume *lv,
struct processing_handle *handle)
{
if (!_lvchange_rebuild(lv))
return_ECMD_FAILED;
return ECMD_PROCESSED;
}
int lvchange_rebuild_cmd(struct cmd_context *cmd, int argc, char **argv)
{
return process_each_lv(cmd, argc, argv, NULL, NULL, READ_FOR_UPDATE, NULL, _lvchange_rebuild_single);
}
static int _lvchange_monitor_poll_single(struct cmd_context *cmd,
struct logical_volume *lv,
struct processing_handle *handle)
{
if (arg_is_set(cmd, monitor_ARG) &&
!_lvchange_monitoring(cmd, lv))
return_ECMD_FAILED;
if (arg_is_set(cmd, poll_ARG) &&
!_lvchange_background_polling(cmd, lv))
return_ECMD_FAILED;
return ECMD_PROCESSED;
}
int lvchange_monitor_poll_cmd(struct cmd_context *cmd, int argc, char **argv)
{
cmd->handles_missing_pvs = 1;
return process_each_lv(cmd, argc, argv, NULL, NULL, 0, NULL, _lvchange_monitor_poll_single);
}
static int _lvchange_persistent_single(struct cmd_context *cmd,
struct logical_volume *lv,
struct processing_handle *handle)
{
if (!_lvchange_persistent(cmd, lv))
return_ECMD_FAILED;
return ECMD_PROCESSED;
}
int lvchange_persistent_cmd(struct cmd_context *cmd, int argc, char **argv)
{
cmd->handles_missing_pvs = 1;
return process_each_lv(cmd, argc, argv, NULL, NULL, READ_FOR_UPDATE, NULL, _lvchange_persistent_single);
}
int lvchange(struct cmd_context *cmd, int argc, char **argv)
{
log_error(INTERNAL_ERROR "Missing function for command definition %s.",
cmd->command->command_line_id);
return ECMD_FAILED;
ret = process_each_lv(cmd, argc, argv, NULL, NULL, 0, handle, _lvchange_refresh_single);
destroy_processing_handle(cmd, handle);
return ret;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1054,12 +1054,6 @@ static int _lvcreate_params(struct cmd_context *cmd,
return 0;
}
if (segtype_is_raid4(lp->segtype) &&
!(lp->target_attr & RAID_FEATURE_RAID4)) {
log_error("RAID module does not support RAID4.");
return 0;
}
if (segtype_is_raid10(lp->segtype) && !(lp->target_attr & RAID_FEATURE_RAID10)) {
log_error("RAID module does not support RAID10.");
return 0;

View File

@@ -79,25 +79,6 @@ struct command_name command_names[MAX_COMMAND_NAMES] = {
#undef xx
};
/*
* Table of LV properties
*/
static struct lv_props _lv_props[LVP_COUNT + 1] = {
#define lvp(a, b, c) {a, b, c},
#include "lv_props.h"
#undef lvp
};
/*
* Table of LV types
*/
static struct lv_types _lv_types[LVT_COUNT + 1] = {
#define lvt(a, b, c) {a, b, c},
#include "lv_types.h"
#undef lvt
};
/*
* Table of valid command lines
*/
@@ -113,50 +94,11 @@ static struct cmdline_context _cmdline;
*/
struct command_function command_functions[COMMAND_ID_COUNT] = {
{ lvmconfig_general_CMD, lvmconfig },
{ lvchange_properties_CMD, lvchange_properties_cmd },
{ lvchange_resync_CMD, lvchange_resync_cmd },
{ lvchange_syncaction_CMD, lvchange_syncaction_cmd },
{ lvchange_rebuild_CMD, lvchange_rebuild_cmd },
{ lvchange_activate_CMD, lvchange_activate_cmd },
{ lvchange_refresh_CMD, lvchange_refresh_cmd },
{ lvchange_monitor_CMD, lvchange_monitor_poll_cmd },
{ lvchange_poll_CMD, lvchange_monitor_poll_cmd },
{ lvchange_persistent_CMD, lvchange_persistent_cmd },
/* lvconvert utilities related to repair. */
{ lvconvert_repair_pvs_or_thinpool_CMD, lvconvert_repair_pvs_or_thinpool_cmd },
{ lvconvert_replace_pv_CMD, lvconvert_replace_pv_cmd },
/* lvconvert utilities related to snapshots. */
{ lvconvert_split_cow_snapshot_CMD, lvconvert_split_snapshot_cmd },
{ lvconvert_merge_snapshot_CMD, lvconvert_merge_snapshot_cmd },
{ lvconvert_combine_split_snapshot_CMD, lvconvert_combine_split_snapshot_cmd },
};
#if 0
/* all raid-related type conversions */
{ lvconvert_raid_types_CMD, lvconvert_raid_types_fn },
/* raid-related utilities (move into lvconvert_raid_types?) */
{ lvconvert_split_mirror_images_CMD, lvconvert_split_mirror_images_fn },
{ lvconvert_change_mirrorlog_CMD, lvconvert_change_mirrorlog_fn },
/* utilities for creating/maintaining thin and cache objects. */
{ lvconvert_to_thin_with_external_CMD, lvconvert_to_thin_with_external_fn },
{ lvconvert_to_cache_vol_CMD, lvconvert_to_cache_vol_fn },
{ lvconvert_to_thinpool_CMD, lvconvert_to_thinpool_fn },
{ lvconvert_to_cachepool_CMD, lvconvert_to_cachepool_fn },
{ lvconvert_split_and_keep_cachepool_CMD, lvconvert_split_and_keep_cachepool_fn },
{ lvconvert_split_and_delete_cachepool_CMD, lvconvert_split_and_delete_cachepool_fn },
{ lvconvert_swap_pool_metadata_CMD, lvconvert_swap_pool_metadata_fn },
/* other misc. */
{ lvconvert_merge_CMD, lvconvert_merge_fn },
{ lvconvert_poll_start_CMD, lvconvert_poll_start_fn },
{ lvchange_properties_CMD, lvchange_properties_cmd },
{ lvchange_activate_CMD, lvchange_activate_cmd },
{ lvchange_refresh_CMD, lvchange_refresh_cmd },
#endif
/* Command line args */
@@ -1112,20 +1054,6 @@ void lvm_register_commands(void)
_set_valid_args_for_command_name(i);
}
struct lv_props *get_lv_prop(int lvp_enum)
{
if (!lvp_enum)
return NULL;
return &_lv_props[lvp_enum];
}
struct lv_types *get_lv_type(int lvt_enum)
{
if (!lvt_enum)
return NULL;
return &_lv_types[lvt_enum];
}
/*
* Also see merge_synonym(). The command definitions
* are written using just one variation of the option
@@ -1451,7 +1379,7 @@ static void _print_description(int ci)
* set to match.
*
* required_pos_args[0].types & select_VAL means
* argv[] in that pos can be NULL if arg_is_set(select_ARG)
* cmd->argv[] in that pos can be NULL if arg_is_set(select_ARG)
*/
/* The max number of unused options we keep track of to warn about */
@@ -1460,7 +1388,6 @@ static void _print_description(int ci)
static struct command *_find_command(struct cmd_context *cmd, const char *path, int *argc, char **argv)
{
const char *name;
char buf[64];
int match_required, match_ro, match_rp, match_type, match_unused, mismatch_required;
int best_i = 0, best_required = 0, best_type = 0, best_unused = 0;
int close_i = 0, close_ro = 0, close_type;
@@ -1468,7 +1395,6 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path,
int temp_unused_count;
int best_unused_options[MAX_UNUSED_COUNT] = { 0 };
int best_unused_count = 0;
int opts_match_count, opts_unmatch_count;
int ro, rp;
int i, j;
int opt_enum, opt_i;
@@ -1693,55 +1619,7 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path,
return NULL;
}
}
out:
/*
* Check any rules related to option combinations.
* Other rules are checked after VG is read.
*/
for (i = 0; i < commands[best_i].rule_count; i++) {
struct cmd_rule *rule;
rule = &commands[best_i].rules[i];
/*
* The rule wants to validate options (check_opts). That can be
* done here if the only qualification for the validation is
* other options (and not specific LV type or LV property which
* are not known here.)
*/
if (rule->check_opts_count && !rule->lvt_bits && !rule->lvp_bits) {
/*
* When no opt is specified for applying the rule, then
* the rule is always applied, otherwise the rule is
* applied when the specific option is set.
*/
if (rule->opts_count &&
!opt_in_list_is_set(cmd, rule->opts, rule->opts_count, NULL, NULL))
continue;
opt_in_list_is_set(cmd, rule->check_opts, rule->check_opts_count,
&opts_match_count, &opts_unmatch_count);
if (opts_match_count && (rule->rule == RULE_INVALID)) {
memset(buf, 0, sizeof(buf));
opt_array_to_str(cmd, rule->check_opts, rule->check_opts_count, buf, sizeof(buf));
log_error("Invalid options for command (%s %d): %s",
commands[best_i].command_line_id, best_i, buf);
return NULL;
}
if (opts_unmatch_count && (rule->rule == RULE_REQUIRE)) {
memset(buf, 0, sizeof(buf));
opt_array_to_str(cmd, rule->check_opts, rule->check_opts_count, buf, sizeof(buf));
log_error("Required options for command (%s %d): %s",
commands[best_i].command_line_id, best_i, buf);
return NULL;
}
}
}
log_debug("command line id: %s %d", commands[best_i].command_line_id, best_i);
return &commands[best_i];
@@ -1800,7 +1678,7 @@ static int _usage(const char *name, int help_count)
log_print(" be omitted if the --select option is used.");
log_print(". --size Number can be replaced with --extents NumberExtents.");
log_print(". When --name is omitted from lvcreate, a new LV name is");
log_print(" generated with the \"lvol\" prefix and a unique numeric suffix.");
log_print(" generated with the \"lvol\" prefix and a unique numeral suffix.");
log_print(". The required VG parameter in lvcreate may be omitted when");
log_print(" the VG name is included in another option, e.g. --name VG/LV.");
log_print(". For required options listed in parentheses, e.g. (--A, --B),");
@@ -2639,12 +2517,6 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
if (!(cmd->command = _find_command(cmd, cmd->name, &argc, argv)))
return EINVALID_CMD_LINE;
/*
* Remaining position args after command name and --options are removed.
*/
cmd->position_argc = argc;
cmd->position_argv = argv;
set_cmd_name(cmd->name);
if (arg_is_set(cmd, backgroundfork_ARG)) {

View File

@@ -194,9 +194,6 @@ static int _pvscan_autoactivate_single(struct cmd_context *cmd, const char *vg_n
if (vg_is_clustered(vg))
return ECMD_PROCESSED;
if (vg_is_exported(vg))
return ECMD_PROCESSED;
if (is_lockd_type(vg->lock_type))
return ECMD_PROCESSED;

View File

@@ -2326,541 +2326,6 @@ 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);
case linear_LVT:
return seg_is_linear(seg);
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);
default:
log_error(INTERNAL_ERROR "unknown lv type value lvt_enum %d", lvt_enum);
}
return 0;
}
static int _get_lvt_enum(struct logical_volume *lv)
{
struct lv_segment *seg = first_seg(lv);
if (seg_is_striped(seg))
return striped_LVT;
if (seg_is_linear(seg))
return linear_LVT;
if (lv_is_cow(lv))
return snapshot_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;
log_error(INTERNAL_ERROR "unknown lv type for %s", display_lvname(lv));
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;
}
/*
* If the command definition specifies one required positional
* LV (possibly repeatable), and specifies accepted LV types,
* then verify that the LV being processed matches one of those
* types.
*
* process_each_lv() can only be used for commands that have
* one positional LV arg (optionally repeating, where each is
* processed independently.) It cannot work for commands that
* have different required LVs in designated positions, like
* 'lvrename LV1 LV2', where each LV is not processed
* independently. That means that this LV type check only
* needs to check the lv_type of the first positional arg.
*/
static int _check_lv_types(struct cmd_context *cmd, struct logical_volume *lv)
{
int ret = 1;
if ((cmd->command->rp_count == 1) &&
val_bit_is_set(cmd->command->required_pos_args[0].def.val_bits, lv_VAL) &&
cmd->command->required_pos_args[0].def.lvt_bits) {
ret = _lv_types_match(cmd, lv, cmd->command->required_pos_args[0].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;
}
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,
@@ -2885,6 +2350,9 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
struct dm_list found_arg_lvnames;
struct glv_list *glvl, *tglvl;
int do_report_ret_code = 1;
uint32_t lv_types;
struct logical_volume *lv;
struct lv_segment *seg;
log_set_report_object_type(LOG_REPORT_OBJECT_TYPE_LV);
@@ -3036,42 +2504,65 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
continue;
/*
* The command definition may include restrictions on the
* types and properties of LVs that can be processed.
* If the command definition specifies one required positional
* LV (possibly repeatable), and specifies accepted LV types,
* then verify that the LV being processed matches one of those
* types.
*
* process_each_lv() can only be used for commands that have
* one positional LV arg (optionally repeating, where each is
* processed independently.) It cannot work for commands that
* have different required LVs in designated positions, like
* 'lvrename LV1 LV2', where each LV is not processed
* independently. That means that this LV type check only
* needs to check the lv_type of the first positional arg.
*
* There is one command that violates this rule by stealing
* the first positional LV arg before calling process_each_lv:
* lvconvert --type snapshot LV_linear_striped_raid LV_snapshot
* This code cannot validate that case. process_each_lv() sees
* a single LV name arg, but it's in pos 2. Could we work around
* this by looking at the final positional arg rather than always
* looking at pos 1?
*
* This only validates types for required LV positional args
* (currently there are no command specifications that include
* specific LV types in optional positional args.)
*/
if (!_check_lv_types(cmd, lvl->lv)) {
/* FIXME: include this result in report log? */
/* FIXME: avoid duplicating message for each level */
if ((cmd->command->rp_count == 1) &&
val_bit_is_set(cmd->command->required_pos_args[0].def.val_bits, lv_VAL) &&
cmd->command->required_pos_args[0].def.lv_types) {
if (str_list_match_item(&found_arg_lvnames, lvl->lv->name)) {
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;
} else {
log_warn("Operation not permitted (%s %d) on LV %s.",
cmd->command->command_line_id, cmd->command->command_line_enum,
display_lvname(lvl->lv));
lv_types = cmd->command->required_pos_args[0].def.lv_types;
lv = lvl->lv;
seg = first_seg(lv);
if ((lv_is_cow(lv) && !(lv_types & ARG_DEF_LV_SNAPSHOT)) ||
(lv_is_thin_volume(lv) && !(lv_types & ARG_DEF_LV_THIN)) ||
(lv_is_thin_pool(lv) && !(lv_types & ARG_DEF_LV_THINPOOL)) ||
(lv_is_cache(lv) && !(lv_types & ARG_DEF_LV_CACHE)) ||
(lv_is_cache_pool(lv) && !(lv_types & ARG_DEF_LV_CACHEPOOL)) ||
(lv_is_mirror(lv) && !(lv_types & ARG_DEF_LV_MIRROR)) ||
(lv_is_raid(lv) && !(lv_types & (ARG_DEF_LV_RAID | ARG_DEF_LV_RAID0 | ARG_DEF_LV_RAID1 | ARG_DEF_LV_RAID4 | ARG_DEF_LV_RAID5 | ARG_DEF_LV_RAID6 | ARG_DEF_LV_RAID10))) ||
(segtype_is_striped(seg->segtype) && !(lv_types & ARG_DEF_LV_STRIPED)) ||
(segtype_is_linear(seg->segtype) && !(lv_types & ARG_DEF_LV_LINEAR))) {
/*
* If a named LV arg cannot be processed it's an error, otherwise
* the LV is skipped and doesn't cause the command to fail.
*/
if (str_list_match_item(&found_arg_lvnames, lv->name)) {
log_error("Operation not permitted (%s %d) on LV %s with type %s.",
cmd->command->command_line_id, cmd->command->command_line_enum,
display_lvname(lv), seg->segtype->name);
ret_max = ECMD_FAILED;
} else {
log_warn("Operation not permitted (%s %d) on LV %s with type %s.",
cmd->command->command_line_id, cmd->command->command_line_enum,
display_lvname(lv), seg->segtype->name);
}
continue;
}
continue;
}
if (!_check_lv_rules(cmd, lvl->lv)) {
/* FIXME: include this result in report log? */
/* FIXME: avoid duplicating message for each level */
if (str_list_match_item(&found_arg_lvnames, lvl->lv->name)) {
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;
} else {
log_warn("Operation not permitted (%s %d) on LV %s.",
cmd->command->command_line_id, cmd->command->command_line_enum,
display_lvname(lvl->lv));
}
continue;
}
log_very_verbose("Processing LV %s in VG %s.", lvl->lv->name, vg->name);

View File

@@ -159,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);

View File

@@ -50,14 +50,14 @@
#define CMD_LEN 256
#define MAX_ARGS 64
/* define the enums for the values accepted by command line --options, foo_VAL */
/* define the enums for the values accepted by command line --options */
enum {
#define val(a, b, c, d) a ,
#include "vals.h"
#undef val
};
/* define the enums for the command line --options, foo_ARG */
/* define the enums for the command line --options */
enum {
#define arg(a, b, c, d, e, f) a ,
#include "args.h"
@@ -69,20 +69,6 @@ enum {
#include "commands.h"
#undef xx
/* define enums for LV properties, foo_LVP */
enum {
#define lvp(a, b, c) a ,
#include "lv_props.h"
#undef lvp
};
/* 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 */
@@ -125,21 +111,6 @@ struct val_props {
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. */
@@ -238,23 +209,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);
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);
#endif

View File

@@ -113,7 +113,7 @@ 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(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")