mirror of
git://sourceware.org/git/lvm2.git
synced 2025-09-28 09:44:18 +03:00
Compare commits
1 Commits
dev-dct-cm
...
dev-dct-cm
Author | SHA1 | Date | |
---|---|---|---|
|
7f02163489 |
@@ -1 +1 @@
|
||||
1.02.137-git (2016-11-05)
|
||||
1.02.136-git (2016-09-26)
|
||||
|
17
WHATS_NEW
17
WHATS_NEW
@@ -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.
|
||||
|
15
WHATS_NEW_DM
15
WHATS_NEW_DM
@@ -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.
|
||||
|
@@ -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)
|
||||
|
@@ -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 */
|
||||
|
@@ -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)
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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 {
|
||||
|
@@ -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.",
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
|
@@ -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):
|
||||
|
@@ -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)
|
||||
|
@@ -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:
|
||||
|
@@ -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,
|
||||
|
@@ -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,
|
||||
|
@@ -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.
|
||||
|
@@ -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()
|
||||
|
@@ -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(
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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.
|
||||
*/
|
||||
|
@@ -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")
|
||||
|
@@ -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';
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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: "
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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;
|
||||
|
@@ -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 */
|
||||
|
@@ -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)
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
*
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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)
|
||||
|
@@ -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;
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
|
@@ -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"
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
|
@@ -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"
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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"
|
||||
|
@@ -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"
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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"
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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
@@ -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;
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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)
|
||||
|
736
tools/lvchange.c
736
tools/lvchange.c
@@ -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
|
||||
|
||||
|
1129
tools/lvconvert.c
1129
tools/lvconvert.c
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
@@ -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)) {
|
||||
|
@@ -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;
|
||||
|
||||
|
625
tools/toollib.c
625
tools/toollib.c
@@ -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);
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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")
|
||||
|
Reference in New Issue
Block a user