mirror of
git://sourceware.org/git/lvm2.git
synced 2025-10-01 21:44:22 +03:00
Compare commits
62 Commits
dev-dct-cm
...
dev-mcsont
Author | SHA1 | Date | |
---|---|---|---|
|
4b84dc8db2 | ||
|
df4f4c1d9e | ||
|
56b2ffddc4 | ||
|
9dc3dfe7b5 | ||
|
f8d41ae850 | ||
|
32f89f6f5b | ||
|
76848c5be9 | ||
|
a7691cdebb | ||
|
6db5b91231 | ||
|
1bdcb01f63 | ||
|
b38564b8dc | ||
|
de3d054f78 | ||
|
4a2250f9ce | ||
|
d8fc4d093e | ||
|
e54cce245f | ||
|
59b29716e5 | ||
|
f8b3b0bc9a | ||
|
b11f4f93d7 | ||
|
0b1c796420 | ||
|
c1862ea84c | ||
|
2ec3e7dca8 | ||
|
ada5733c56 | ||
|
9e03fc3c2a | ||
|
eed708dbd9 | ||
|
6dce0e9489 | ||
|
461d340bd7 | ||
|
ee0c9e7b23 | ||
|
a9ee86ccf2 | ||
|
4e26024add | ||
|
0d95082aa9 | ||
|
9cbe4c1af9 | ||
|
cc19cc07f7 | ||
|
e3775173b4 | ||
|
ee13f265f0 | ||
|
221d8ff2a4 | ||
|
28b210f4fa | ||
|
1db4b81d5a | ||
|
4b4d19e3aa | ||
|
cd468b6218 | ||
|
33dd1f7747 | ||
|
e50d434a35 | ||
|
6af26273cb | ||
|
96118a2508 | ||
|
95abadd13c | ||
|
60de09b00c | ||
|
38dd79307a | ||
|
24803bbaad | ||
|
c8e8439b3d | ||
|
68e7d34965 | ||
|
4585785613 | ||
|
a9651adc84 | ||
|
e611f82a11 | ||
|
8270ff5702 | ||
|
e118b65d65 | ||
|
61ae07966d | ||
|
ff05ed7afd | ||
|
e84f527cd3 | ||
|
0468f5da6d | ||
|
021715e897 | ||
|
5eda393488 | ||
|
de78e8eae7 | ||
|
34da83d729 |
@@ -1 +1 @@
|
||||
1.02.136-git (2016-09-26)
|
||||
1.02.137-git (2016-11-05)
|
||||
|
16
WHATS_NEW
16
WHATS_NEW
@@ -1,5 +1,17 @@
|
||||
Version 2.02.167 -
|
||||
======================================
|
||||
Version 2.02.168 -
|
||||
====================================
|
||||
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*
|
||||
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,5 +1,16 @@
|
||||
Version 1.02.136 -
|
||||
======================================
|
||||
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.
|
||||
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,13 +99,28 @@ static time_t _idle_since = 0;
|
||||
static char **_initial_registrations = 0;
|
||||
|
||||
/* FIXME Make configurable at runtime */
|
||||
__attribute__((format(printf, 4, 5)))
|
||||
static void _dmeventd_log(int level, const char *file, int line,
|
||||
const char *format, ...)
|
||||
|
||||
/* 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, 0, format, ap);
|
||||
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)))
|
||||
static void _dmeventd_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("dmeventd", level, file, line, dm_errno_or_class, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
@@ -2191,7 +2206,7 @@ int main(int argc, char *argv[])
|
||||
openlog("dmeventd", LOG_PID, LOG_DAEMON);
|
||||
|
||||
dm_event_log_set(_debug_level, _use_syslog);
|
||||
dm_log_init(_dmeventd_log);
|
||||
dm_log_with_errno_init(_libdm_log);
|
||||
|
||||
(void) dm_prepare_selinux_context(DMEVENTD_PIDFILE, S_IFREG);
|
||||
if (dm_create_lockfile(DMEVENTD_PIDFILE) == 0)
|
||||
|
@@ -865,28 +865,38 @@ 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 = stdout;
|
||||
FILE *stream = log_stderr(level) ? stderr : stdout;
|
||||
int prio;
|
||||
time_t now;
|
||||
int log_with_debug = 0;
|
||||
|
||||
switch (level & ~(_LOG_STDERR | _LOG_ONCE)) {
|
||||
if (subsys[0] == '#') {
|
||||
/* Subsystems starting with '#' are logged
|
||||
* only when debugging is enabled. */
|
||||
log_with_debug++;
|
||||
subsys++;
|
||||
}
|
||||
|
||||
switch (log_level(level)) {
|
||||
case _LOG_DEBUG:
|
||||
/* Never shown without -ddd */
|
||||
if (_debug_level < 3)
|
||||
return;
|
||||
prio = LOG_DEBUG;
|
||||
indent = " ";
|
||||
break;
|
||||
case _LOG_INFO:
|
||||
if (_debug_level < 2)
|
||||
if (log_with_debug && _debug_level < 2)
|
||||
return;
|
||||
prio = LOG_INFO;
|
||||
indent = " ";
|
||||
break;
|
||||
case _LOG_NOTICE:
|
||||
if (_debug_level < 1)
|
||||
if (log_with_debug && _debug_level < 1)
|
||||
return;
|
||||
prio = LOG_NOTICE;
|
||||
indent = " ";
|
||||
@@ -912,12 +922,13 @@ void dm_event_log(const char *subsys, int level, const char *file,
|
||||
if (!start)
|
||||
start = now;
|
||||
now -= start;
|
||||
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)
|
||||
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);
|
||||
@@ -926,6 +937,15 @@ 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,8 +73,10 @@ 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))
|
||||
goto_out;
|
||||
if (!dm_get_status_mirror(state->mem, params, &ms)) {
|
||||
log_error("Unable to parse mirror status string.");
|
||||
return ME_IGNORE;
|
||||
}
|
||||
|
||||
/* Check for bad mirror devices */
|
||||
for (i = 0; i < ms->dev_count; ++i)
|
||||
@@ -95,27 +97,23 @@ 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)
|
||||
static int _remove_failed_devices(const char *cmd_lvscan, const char *cmd_lvconvert,
|
||||
const char *device)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!dmeventd_lvm2_run_with_lock(cmd_lvscan))
|
||||
log_info("Re-scan of mirrored device failed.");
|
||||
log_warn("WARNING: Re-scan of mirrored device %s failed.", device);
|
||||
|
||||
/* if repair goes OK, report success even if lvscan has failed */
|
||||
r = dmeventd_lvm2_run_with_lock(cmd_lvconvert);
|
||||
if (!dmeventd_lvm2_run_with_lock(cmd_lvconvert)) {
|
||||
log_error("Repair of mirrored device %s failed.", device);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_info("Repair of mirrored device %s.",
|
||||
(r) ? "finished successfully" : "failed");
|
||||
log_info("Repair of mirrored device %s finished successfully.", device);
|
||||
|
||||
return r;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void process_event(struct dm_task *dmt,
|
||||
@@ -154,7 +152,8 @@ 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))
|
||||
state->cmd_lvconvert,
|
||||
device))
|
||||
/* FIXME Why are all the error return codes unused? Get rid of them? */
|
||||
log_error("Failed to remove faulty devices in %s.",
|
||||
device);
|
||||
@@ -168,7 +167,7 @@ void process_event(struct dm_task *dmt,
|
||||
break;
|
||||
default:
|
||||
/* FIXME Provide value then! */
|
||||
log_info("Unknown event received.");
|
||||
log_warn("WARNING: %s received unknown event.", device);
|
||||
}
|
||||
} 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_info("Repair of RAID device %s failed.", device);
|
||||
log_error("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_info("dmeventd executes: %s.", state->cmd_str);
|
||||
log_debug("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,19 +7,13 @@
|
||||
# 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):
|
||||
@@ -42,15 +36,40 @@ def lv_merge_cmd(merge_options, lv_full_name):
|
||||
return cmd
|
||||
|
||||
|
||||
def _move_merge(interface_name, cmd, job_state):
|
||||
add(cmd, job_state)
|
||||
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)
|
||||
|
||||
done = job_state.Wait(-1)
|
||||
if not done:
|
||||
ec, err_msg = job_state.GetError
|
||||
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:
|
||||
raise dbus.exceptions.DBusException(
|
||||
interface_name,
|
||||
'Exit code %s, stderr = %s' % (str(ec), err_msg))
|
||||
'Exit code %s, stderr = %s' % (str(process.returncode), out[1]))
|
||||
|
||||
cfg.load()
|
||||
return '/'
|
||||
@@ -85,8 +104,6 @@ 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,
|
||||
@@ -109,106 +126,3 @@ 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,20 +11,37 @@ 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 load(refresh=True, emit_signal=True, cache_refresh=True, log=True):
|
||||
def _main_thread_load(refresh=True, emit_signal=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)
|
||||
|
||||
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]
|
||||
if need_main_thread:
|
||||
rc = MThreadRunner(_main_thread_load, refresh, emit_signal).done()
|
||||
else:
|
||||
rc = _main_thread_load(refresh, emit_signal)
|
||||
|
||||
return num_total_changes
|
||||
return rc
|
||||
|
@@ -8,12 +8,54 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from .automatedproperties import AutomatedProperties
|
||||
from .utils import job_obj_path_generate
|
||||
from .utils import job_obj_path_generate, mt_async_result, log_debug
|
||||
from . import cfg
|
||||
from .cfg import JOB_INTERFACE
|
||||
import dbus
|
||||
import threading
|
||||
from . import background
|
||||
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
|
||||
|
||||
|
||||
# noinspection PyPep8Naming
|
||||
@@ -24,9 +66,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
|
||||
@@ -57,7 +99,7 @@ class JobState(object):
|
||||
with self.rlock:
|
||||
self._complete = value
|
||||
self._percent = 100
|
||||
self._cond.notify_all()
|
||||
self.notify_waiting_clients()
|
||||
|
||||
@property
|
||||
def GetError(self):
|
||||
@@ -71,29 +113,10 @@ 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:
|
||||
@@ -101,6 +124,36 @@ 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):
|
||||
@@ -122,10 +175,6 @@ 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)
|
||||
@@ -138,9 +187,6 @@ 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:
|
||||
@@ -155,7 +201,11 @@ class Job(AutomatedProperties):
|
||||
out_signature='b',
|
||||
async_callbacks=('cb', 'cbe'))
|
||||
def Wait(self, timeout, cb, cbe):
|
||||
background.add_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))
|
||||
|
||||
@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
|
||||
from .utils import round_size, mt_remove_dbus_objects
|
||||
from .job import JobState
|
||||
|
||||
|
||||
@@ -415,7 +415,6 @@ 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
|
||||
@@ -515,15 +514,9 @@ class Lv(LvCommon):
|
||||
rc, out, err = cmdhandler.vg_lv_snapshot(
|
||||
lv_name, snapshot_options, name, optional_size)
|
||||
if rc == 0:
|
||||
return_path = '/'
|
||||
cfg.load()
|
||||
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
|
||||
lvs = load_lvs([full_name], emit_signal=True)[0]
|
||||
for l in lvs:
|
||||
return_path = l.dbus_object_path()
|
||||
|
||||
# Refresh self and all included PVs
|
||||
cfg.load(cache_refresh=False)
|
||||
return return_path
|
||||
return cfg.om.get_object_path_by_lvm_id(full_name)
|
||||
else:
|
||||
raise dbus.exceptions.DBusException(
|
||||
LV_INTERFACE,
|
||||
@@ -752,9 +745,8 @@ class LvThinPool(Lv):
|
||||
lv_name, create_options, name, size_bytes)
|
||||
if rc == 0:
|
||||
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
|
||||
lvs = load_lvs([full_name], emit_signal=True)[0]
|
||||
for l in lvs:
|
||||
lv_created = l.dbus_object_path()
|
||||
cfg.load()
|
||||
lv_created = cfg.om.get_object_path_by_lvm_id(full_name)
|
||||
else:
|
||||
raise dbus.exceptions.DBusException(
|
||||
LV_INTERFACE,
|
||||
@@ -816,8 +808,7 @@ 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!
|
||||
cfg.om.remove_object(dbo, emit_signal=True)
|
||||
cfg.om.remove_object(lv_to_cache, emit_signal=True)
|
||||
mt_remove_dbus_objects((dbo, lv_to_cache))
|
||||
cfg.load()
|
||||
|
||||
lv_converted = cfg.om.get_object_path_by_lvm_id(fcn)
|
||||
@@ -879,8 +870,7 @@ class LvCacheLv(Lv):
|
||||
if rc == 0:
|
||||
# The cache pool gets removed as hidden and put back to
|
||||
# visible, so lets delete
|
||||
cfg.om.remove_object(cache_pool, emit_signal=True)
|
||||
cfg.om.remove_object(dbo, emit_signal=True)
|
||||
mt_remove_dbus_objects((cache_pool, dbo))
|
||||
cfg.load()
|
||||
|
||||
uncached_lv_path = cfg.om.get_object_path_by_lvm_id(lv_name)
|
||||
|
@@ -22,7 +22,6 @@ 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
|
||||
@@ -64,6 +63,7 @@ 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("Complete ")
|
||||
log_debug("Method complete ")
|
||||
except queue.Empty:
|
||||
pass
|
||||
except Exception:
|
||||
@@ -156,14 +156,11 @@ def main():
|
||||
|
||||
cfg.db = lvmdb.DataStore(cfg.args.use_json)
|
||||
|
||||
# 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.
|
||||
# Using a thread to process requests, we cannot hang the dbus library
|
||||
# thread that is handling the dbus interface
|
||||
thread_list.append(threading.Thread(target=process_request))
|
||||
|
||||
cfg.load(refresh=False, emit_signal=False)
|
||||
cfg.load(refresh=False, emit_signal=False, need_main_thread=False)
|
||||
cfg.loop = GLib.MainLoop()
|
||||
|
||||
for process in thread_list:
|
||||
|
@@ -42,12 +42,10 @@ 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:
|
||||
pvs = load_pvs([device], emit_signal=True)[0]
|
||||
for p in pvs:
|
||||
created_pv = p.dbus_object_path()
|
||||
cfg.load()
|
||||
created_pv = cfg.om.get_object_path_by_lvm_id(device)
|
||||
else:
|
||||
raise dbus.exceptions.DBusException(
|
||||
MANAGER_INTERFACE,
|
||||
@@ -80,20 +78,14 @@ 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:
|
||||
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)
|
||||
cfg.load()
|
||||
return cfg.om.get_object_path_by_lvm_id(name)
|
||||
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
|
||||
from .utils import round_size, mt_remove_dbus_objects
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
@@ -140,7 +140,7 @@ class Pv(AutomatedProperties):
|
||||
if dbo:
|
||||
rc, out, err = cmdhandler.pv_remove(pv_name, remove_options)
|
||||
if rc == 0:
|
||||
cfg.om.remove_object(dbo, True)
|
||||
mt_remove_dbus_objects((dbo,))
|
||||
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:
|
||||
dbo.refresh()
|
||||
cfg.load()
|
||||
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
|
||||
from .utils import log_error, mt_async_result
|
||||
|
||||
|
||||
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:
|
||||
self.cb(('/', self._job.dbus_object_path()))
|
||||
mt_async_result(self.cb, ('/', self._job.dbus_object_path()))
|
||||
else:
|
||||
self.cb(self._job.dbus_object_path())
|
||||
mt_async_result(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:
|
||||
self.cb((result, '/'))
|
||||
mt_async_result(self.cb, (result, '/'))
|
||||
else:
|
||||
self.cb(result)
|
||||
mt_async_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)
|
||||
|
||||
self.cb_error(error_exception)
|
||||
mt_async_result(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,6 +17,8 @@ import datetime
|
||||
|
||||
import dbus
|
||||
from lvmdbusd import cfg
|
||||
from gi.repository import GLib
|
||||
import threading
|
||||
|
||||
|
||||
STDOUT_TTY = os.isatty(sys.stdout.fileno())
|
||||
@@ -494,3 +496,64 @@ 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
|
||||
from .utils import round_size, mt_remove_dbus_objects
|
||||
from .job import JobState
|
||||
|
||||
|
||||
@@ -191,14 +191,7 @@ 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(
|
||||
@@ -605,9 +598,7 @@ class Vg(AutomatedProperties):
|
||||
rc, out, err = create_method(
|
||||
md.lv_full_name(), data.lv_full_name(), create_options)
|
||||
if rc == 0:
|
||||
cfg.om.remove_object(md, emit_signal=True)
|
||||
cfg.om.remove_object(data, emit_signal=True)
|
||||
|
||||
mt_remove_dbus_objects((md, data))
|
||||
cache_pool_lv = Vg.fetch_new_lv(vg_name, new_name)
|
||||
else:
|
||||
raise dbus.exceptions.DBusException(
|
||||
|
@@ -370,6 +370,11 @@ 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;
|
||||
@@ -1489,6 +1494,26 @@ 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);
|
||||
@@ -1683,7 +1708,7 @@ int target_register_events(struct cmd_context *cmd, const char *dso, const struc
|
||||
if (!r)
|
||||
return_0;
|
||||
|
||||
log_info("%s %s for events", set ? "Monitored" : "Unmonitored", uuid);
|
||||
log_very_verbose("%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-2012 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -99,6 +99,7 @@ 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_device(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
struct lv_segment *seg, int s)
|
||||
static char *_add_error_or_zero_device(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
struct lv_segment *seg, int s, int use_zero)
|
||||
{
|
||||
char *dlid, *name;
|
||||
char errid[32];
|
||||
@@ -2262,13 +2262,15 @@ static char *_add_error_device(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
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("_add_error_device called with bad segment");
|
||||
log_error(INTERNAL_ERROR "_add_error_or_zero_device called with bad segment.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -2281,7 +2283,7 @@ static char *_add_error_device(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
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;
|
||||
@@ -2291,14 +2293,19 @@ static char *_add_error_device(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
/* Create new node */
|
||||
if (!(node = dm_tree_add_new_dev(dtree, name, dlid, 0, 0, 0, 0, 0)))
|
||||
return_NULL;
|
||||
if (!dm_tree_node_add_error_target(node, size))
|
||||
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;
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2310,14 +2317,15 @@ 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)) {
|
||||
if (!strcmp(dm->cmd->stripe_filler, TARGET_NAME_ERROR) || use_zero) {
|
||||
/*
|
||||
* 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_device(dm, *tree, seg, s)))
|
||||
if (!(dlid = _add_error_or_zero_device(dm, *tree, seg, s, use_zero)))
|
||||
return_0;
|
||||
if (!dm_tree_node_add_target_area(node, NULL, dlid, extent_size * seg_le(seg, s)))
|
||||
return_0;
|
||||
@@ -2825,7 +2833,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";
|
||||
|
||||
if (strcmp(cmd->stripe_filler, "error")) {
|
||||
else if (strcmp(cmd->stripe_filler, "error") &&
|
||||
strcmp(cmd->stripe_filler, "zero")) {
|
||||
if (stat(cmd->stripe_filler, &st)) {
|
||||
log_warn("WARNING: activation/missing_stripe_filler = \"%s\" "
|
||||
"is invalid,", cmd->stripe_filler);
|
||||
|
@@ -88,10 +88,9 @@ struct cmd_context {
|
||||
* Command line and arguments.
|
||||
*/
|
||||
const char *cmd_line;
|
||||
const char *name; /* needed before cmd->command is set */
|
||||
struct command *command;
|
||||
char **argv;
|
||||
struct arg_values *opt_arg_values;
|
||||
struct arg_values *arg_values;
|
||||
struct dm_list arg_value_groups;
|
||||
|
||||
/*
|
||||
|
@@ -1111,7 +1111,8 @@ 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. You can instead use a device path, in which case,\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"
|
||||
"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_info("pattern must begin with 'a' or 'r'");
|
||||
log_error("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_info("invalid separator at end of regex");
|
||||
log_error("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_info("sysfs device file not correct format");
|
||||
log_error("Incorrect format for sysfs device file: %s.", file);
|
||||
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_info("%s: Label for sector %" PRIu64
|
||||
" found at sector %" PRIu64
|
||||
" - ignoring", dev_name(dev),
|
||||
(uint64_t)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);
|
||||
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_info("Label checksum incorrect on %s - "
|
||||
"ignoring", dev_name(dev));
|
||||
log_very_verbose("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_info("%s: Wiping label at sector %" PRIu64,
|
||||
dev_name(dev), sector);
|
||||
log_very_verbose("%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_info("%s: Writing label to sector %" PRIu64 " with stored offset %"
|
||||
PRIu32 ".", dev_name(dev), label->sector,
|
||||
xlate32(lh->offset_xl));
|
||||
log_very_verbose("%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;
|
||||
};
|
||||
|
||||
struct log_stream {
|
||||
static 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 = level & _LOG_STDERR;
|
||||
int log_once = level & _LOG_ONCE;
|
||||
int log_bypass_report = level & _LOG_BYPASS_REPORT;
|
||||
int use_stderr = log_stderr(level);
|
||||
int log_once = log_once(level);
|
||||
int log_bypass_report = log_bypass_report(level);
|
||||
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_STDERR|_LOG_ONCE|_LOG_BYPASS_REPORT);
|
||||
level = log_level(level);
|
||||
|
||||
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 (!(level & _LOG_STDERR) &&
|
||||
((level & ~(_LOG_STDERR|_LOG_ONCE|_LOG_BYPASS_REPORT)) == _LOG_WARN))
|
||||
if (!log_stderr(level) &&
|
||||
(log_level(level) == _LOG_WARN))
|
||||
level |= _LOG_BYPASS_REPORT;
|
||||
|
||||
_log_stream.out.stream = report_stream;
|
||||
|
@@ -50,6 +50,10 @@
|
||||
#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-2013 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -1418,6 +1418,7 @@ 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";
|
||||
@@ -1454,6 +1455,9 @@ 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));
|
||||
@@ -1468,6 +1472,9 @@ 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))
|
||||
@@ -1476,6 +1483,9 @@ 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));
|
||||
@@ -1488,6 +1498,10 @@ 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)
|
||||
|
@@ -3844,6 +3844,7 @@ 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,45 +3918,60 @@ static int _lv_extend_layered_lv(struct alloc_handle *ah,
|
||||
if (!vg_write(lv->vg) || !vg_commit(lv->vg))
|
||||
return_0;
|
||||
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
meta_lv = seg_metalv(seg, s);
|
||||
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);
|
||||
|
||||
if (test_mode()) {
|
||||
lv_set_hidden(meta_lv);
|
||||
continue;
|
||||
if (!activate_lv_local(meta_lv->vg->cmd, meta_lv)) {
|
||||
log_error("Failed to activate %s for clearing.",
|
||||
display_lvname(meta_lv));
|
||||
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;
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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);
|
||||
if (fail)
|
||||
/* Fail, after trying to deactivate all we could */
|
||||
return_0;
|
||||
}
|
||||
|
||||
for (s = 0; s < seg->area_count; s++)
|
||||
lv_set_hidden(seg_metalv(seg, s));
|
||||
}
|
||||
|
||||
seg->area_len += extents / area_multiple;
|
||||
|
@@ -1208,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, struct dm_list *remove_pvs,
|
||||
struct dm_list *allocate_pvs);
|
||||
int lv_raid_replace(struct logical_volume *lv, int force,
|
||||
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,19 +266,16 @@ 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;
|
||||
|
||||
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) {
|
||||
do {
|
||||
/*
|
||||
* FIXME We repeat the status read here to workaround an
|
||||
* unresolved kernel bug when we see 0 even though the
|
||||
@@ -290,14 +287,34 @@ static int _raid_in_sync(struct logical_volume *lv)
|
||||
lv->vg->name, lv->name);
|
||||
return 0;
|
||||
}
|
||||
if (sync_percent == DM_PERCENT_100)
|
||||
if (sync_percent > DM_PERCENT_0)
|
||||
break;
|
||||
if (retries == _RAID_IN_SYNC_RETRIES)
|
||||
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
|
||||
@@ -1039,10 +1056,10 @@ static int _extract_image_components(struct lv_segment *seg, uint32_t idx,
|
||||
seg_metatype(seg, idx) = AREA_UNASSIGNED;
|
||||
|
||||
/* FIXME Remove duplicated prefix? */
|
||||
if (!(data_lv->name = _generate_raid_name(data_lv, "_extracted", -1)))
|
||||
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;
|
||||
@@ -1054,6 +1071,7 @@ 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().
|
||||
@@ -1068,7 +1086,8 @@ 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, uint32_t new_count,
|
||||
static int _raid_extract_images(struct logical_volume *lv,
|
||||
int force, uint32_t new_count,
|
||||
struct dm_list *target_pvs, int shift,
|
||||
struct dm_list *extracted_meta_lvs,
|
||||
struct dm_list *extracted_data_lvs)
|
||||
@@ -1136,11 +1155,16 @@ static int _raid_extract_images(struct logical_volume *lv, uint32_t new_count,
|
||||
!lv_is_on_pvs(seg_metalv(seg, s), target_pvs))
|
||||
continue;
|
||||
|
||||
if (!_raid_in_sync(lv) &&
|
||||
(!seg_is_mirrored(seg) || (s == 0))) {
|
||||
/*
|
||||
* 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))) {
|
||||
log_error("Unable to extract %sRAID image"
|
||||
" while RAID array is not in-sync",
|
||||
seg_is_mirrored(seg) ? "primary " : "");
|
||||
" while RAID array is not in-sync%s",
|
||||
seg_is_mirrored(seg) ? "primary " : "",
|
||||
seg_is_mirrored(seg) ? " (use --force option to replace)" : "");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1185,7 +1209,7 @@ static int _raid_remove_images(struct logical_volume *lv,
|
||||
if (!removal_lvs)
|
||||
removal_lvs = &removed_lvs;
|
||||
|
||||
if (!_raid_extract_images(lv, new_count, allocate_pvs, 1,
|
||||
if (!_raid_extract_images(lv, 0, new_count, allocate_pvs, 1,
|
||||
removal_lvs, removal_lvs)) {
|
||||
log_error("Failed to extract images from %s/%s",
|
||||
lv->vg->name, lv->name);
|
||||
@@ -1375,7 +1399,7 @@ int lv_raid_split(struct logical_volume *lv, const char *split_name,
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!_raid_extract_images(lv, new_count, splittable_pvs, 1,
|
||||
if (!_raid_extract_images(lv, 0, new_count, splittable_pvs, 1,
|
||||
&removal_lvs, &data_list)) {
|
||||
log_error("Failed to extract images from %s/%s",
|
||||
lv->vg->name, lv->name);
|
||||
@@ -2459,7 +2483,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 segement for LV %s.", display_lvname(lv));
|
||||
log_error("Failed to allocate new raid0 segment for LV %s.", display_lvname(lv));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -2519,42 +2543,51 @@ 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 },
|
||||
.options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
|
||||
{ .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, i.e. seg->area_count > 1 */
|
||||
{ .current_types = SEG_STRIPED_TARGET, /* striped -> raid0*, 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, /* seg->area_count > 1 */
|
||||
{ .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 */
|
||||
.possible_types = SEG_RAID4,
|
||||
.current_areas = ~0U,
|
||||
.options = ALLOW_NONE },
|
||||
{ .current_types = SEG_RAID0|SEG_RAID0_META, /* raid0 striped, i.e. seg->area_count > 0 */
|
||||
.options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
|
||||
/* raid4 -> -> */
|
||||
{ .current_types = SEG_RAID4, /* raid4 ->striped/raid0*, i.e. seg->area_count > 1 */
|
||||
.possible_types = SEG_STRIPED_TARGET|SEG_RAID0|SEG_RAID0_META,
|
||||
.current_areas = ~0U,
|
||||
.options = ALLOW_NONE },
|
||||
/* raid1 -> */
|
||||
/* raid1 -> mirror */
|
||||
{ .current_types = SEG_RAID1,
|
||||
.possible_types = SEG_RAID1|SEG_MIRROR,
|
||||
.possible_types = SEG_MIRROR,
|
||||
.current_areas = ~0U,
|
||||
.options = ALLOW_NONE },
|
||||
.options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
|
||||
/* mirror -> raid1 with arbitrary number of legs */
|
||||
{ .current_types = SEG_MIRROR,
|
||||
.possible_types = SEG_MIRROR|SEG_RAID1,
|
||||
.possible_types = SEG_RAID1,
|
||||
.current_areas = ~0U,
|
||||
.options = ALLOW_NONE },
|
||||
{ .current_types = SEG_RAID4,
|
||||
.possible_types = SEG_STRIPED_TARGET|SEG_RAID0|SEG_RAID0_META,
|
||||
.current_areas = ~0U,
|
||||
.options = ALLOW_NONE },
|
||||
.options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
|
||||
|
||||
/* END */
|
||||
{ .current_types = 0 }
|
||||
@@ -2861,9 +2894,176 @@ 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;
|
||||
|
||||
@@ -2879,10 +3079,39 @@ 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;
|
||||
@@ -2902,7 +3131,19 @@ static int _raid456_to_raid0_or_striped_wrapper(TAKEOVER_FN_ARGS)
|
||||
|
||||
seg->region_size = 0;
|
||||
|
||||
return _lv_update_reload_fns_reset_eliminate_lvs(lv, &removal_lvs);
|
||||
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;
|
||||
}
|
||||
|
||||
static int _striped_to_raid0_wrapper(struct logical_volume *lv,
|
||||
@@ -2930,6 +3171,9 @@ 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);
|
||||
@@ -2944,6 +3188,13 @@ 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;
|
||||
@@ -2961,7 +3212,10 @@ 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),
|
||||
@@ -2969,8 +3223,9 @@ 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)) {
|
||||
/* Can't convert striped/raid0* to e.g. raid10_offset */
|
||||
if (segtype_is_raid4(new_segtype) &&
|
||||
(!_shift_parity_dev(seg) ||
|
||||
!_rename_area_lvs(lv, "_"))) {
|
||||
log_error("Can't convert %s to %s", display_lvname(lv), new_segtype->name);
|
||||
return 0;
|
||||
}
|
||||
@@ -2987,6 +3242,14 @@ 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;
|
||||
}
|
||||
|
||||
@@ -3630,6 +3893,7 @@ 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)
|
||||
@@ -3804,7 +4068,8 @@ try_again:
|
||||
* supplied - knowing that only the image with the error target
|
||||
* will be affected.
|
||||
*/
|
||||
if (!_raid_extract_images(lv, raid_seg->area_count - match_count,
|
||||
if (!_raid_extract_images(lv, force,
|
||||
raid_seg->area_count - match_count,
|
||||
partial_segment_removed ?
|
||||
&lv->vg->pvs : remove_pvs, 0,
|
||||
&old_lvs, &old_lvs)) {
|
||||
@@ -3909,7 +4174,7 @@ skip_alloc:
|
||||
int lv_raid_rebuild(struct logical_volume *lv,
|
||||
struct dm_list *rebuild_pvs)
|
||||
{
|
||||
return _lv_raid_rebuild_or_replace(lv, rebuild_pvs, NULL, 1);
|
||||
return _lv_raid_rebuild_or_replace(lv, 0, rebuild_pvs, NULL, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3922,10 +4187,11 @@ 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, remove_pvs, allocate_pvs, 0);
|
||||
return _lv_raid_rebuild_or_replace(lv, force, 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-2015 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -268,6 +268,7 @@ 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);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2011-2013 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2016 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 int _raid_attrs = 0;
|
||||
static unsigned _raid_attrs = 0;
|
||||
uint32_t maj, min, patchlevel;
|
||||
unsigned i;
|
||||
|
||||
@@ -389,6 +389,12 @@ 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 = (level & _LOG_STDERR) ? stderr : stdout;
|
||||
FILE *out = log_stderr(level) ? stderr : stdout;
|
||||
|
||||
level &= ~(_LOG_STDERR | _LOG_BYPASS_REPORT);
|
||||
level = log_level(level);
|
||||
|
||||
if (level <= _LOG_WARN || _verbose) {
|
||||
if (level < _LOG_WARN)
|
||||
@@ -137,8 +137,7 @@ static void _default_log_line(int level,
|
||||
|
||||
__attribute__((format(printf, 5, 6)))
|
||||
static void _default_log_with_errno(int level,
|
||||
const char *file __attribute__((unused)),
|
||||
int line __attribute__((unused)), int dm_errno_or_class,
|
||||
const char *file, int line, int dm_errno_or_class,
|
||||
const char *f, ...)
|
||||
{
|
||||
va_list ap;
|
||||
@@ -162,29 +161,75 @@ 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;
|
||||
else
|
||||
dm_log_with_errno = _log_to_default_log;
|
||||
} 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) ? 0 : 1;
|
||||
return (dm_log == _default_log && dm_log_with_errno == _default_log_with_errno) ? 0 : 1;
|
||||
}
|
||||
|
||||
void dm_log_with_errno_init(dm_log_with_errno_fn fn)
|
||||
{
|
||||
if (fn)
|
||||
if (fn) {
|
||||
dm_log = _log_to_default_log_with_errno;
|
||||
dm_log_with_errno = fn;
|
||||
else
|
||||
} else {
|
||||
dm_log = _default_log;
|
||||
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("Grouping regions with different clock resolution: "
|
||||
"precision may be lost");
|
||||
log_warn("WARNING: Grouping regions with different clock resolution: "
|
||||
"precision may be lost.");
|
||||
|
||||
if (!_stats_group_check_overlap(dms, regions, count))
|
||||
log_info("Creating group with overlapping regions");
|
||||
log_very_verbose("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("Failed to delete region "
|
||||
log_warn("WARNING: 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_info("Creating group with overlapping regions.");
|
||||
log_very_verbose("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-2007 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -18,16 +18,10 @@
|
||||
|
||||
#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...) \
|
||||
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)
|
||||
dm_log_with_errno(l, f, ln, e, ## x)
|
||||
|
||||
#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,6 +365,9 @@ See corresponding operation --splitmirrors.
|
||||
VG/RaidLV
|
||||
.br
|
||||
\[bu]
|
||||
Options \-\-background, \-\-interval.
|
||||
.br
|
||||
\[bu]
|
||||
Replace failed PVs in RaidLV.
|
||||
|
||||
.B lvconvert \-\-replace
|
||||
@@ -502,6 +505,9 @@ 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,6 +34,7 @@ TOOL=blkdeactivate
|
||||
DEV_DIR='/dev'
|
||||
SYS_BLK_DIR='/sys/block'
|
||||
|
||||
MOUNTPOINT="/bin/mountpoint"
|
||||
UMOUNT="/bin/umount"
|
||||
DMSETUP="@sbindir@/dmsetup"
|
||||
LVM="@sbindir@/lvm"
|
||||
@@ -157,9 +158,11 @@ 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"
|
||||
else
|
||||
elif $MOUNTPOINT -q "$mnt"; then
|
||||
echo "skipping"
|
||||
add_device_to_skip_list
|
||||
else
|
||||
echo "already unmounted"
|
||||
fi
|
||||
else
|
||||
echo " [SKIP]: unmount of $name ($kname) mounted on $mnt"
|
||||
|
@@ -14,7 +14,7 @@
|
||||
# on those systems.
|
||||
|
||||
# A macro to pull in an include file from an appropriate location.
|
||||
%define import() %include %(test -e %{S:%1} && echo %{S:%1} || echo %{_sourcedir}/%1)
|
||||
%global import() %%include %%(test -e %%{S:%%1} && echo %%{S:%%1} || echo %%{_sourcedir}/%%1)
|
||||
|
||||
%import source.inc
|
||||
|
||||
|
@@ -14,70 +14,73 @@
|
||||
%global rhel 0
|
||||
%endif
|
||||
|
||||
%define enableif() \
|
||||
%global configure_flags %{?configure_flags} --%(if test %1 -gt 0; then echo enable-%2; else echo disable-%2; fi)
|
||||
# TODO: This will disable feature, even though configure could enable it if requirements were met:
|
||||
# SUGGESTION: rename this to enableiff - "if and only if" and use weaker enableif not producing disable flag
|
||||
# NOTE: It is in some cases guarded by another if, so may not produce anything...
|
||||
%global enableif() \
|
||||
%%global configure_flags %%{?configure_flags} --%%(if test %%1 -gt 0; then echo enable-%%2; else echo disable-%%2; fi)
|
||||
|
||||
%define with() \
|
||||
%global configure_flags %(echo -n "%{?configure_flags} " | sed -e "s,--with-%1=[^ ]*,,"; test -n "%{?2}" && echo --with-%1=%2) \
|
||||
%global with_flags %(echo -n "%{?with_flags} " | sed -e "s,%1,,"; test -n "%{?2}" && test "%{?2}" != none && echo %1)
|
||||
%global with() \
|
||||
%%global configure_flags %%(echo -n "%%{?configure_flags} " | sed -e "s,--with-%%1=[^ ]*,,"; test -n "%%{?2}" && echo --with-%%1=%%2) \
|
||||
%%global with_flags %%(echo -n "%%{?with_flags} " | sed -e "s,%%1,,"; test -n "%%{?2}" && test "%%{?2}" != none && echo %%1)
|
||||
|
||||
%global services monitor
|
||||
%define service() \
|
||||
%global services %(echo -n "%{?services} " | sed -e s,%1,,; test "%2" = 1 && echo %1)
|
||||
%global service() \
|
||||
%%global services %%(echo -n "%%{?services} " | sed -e s,%%1,,; test "%%2" = 1 && echo %%1)
|
||||
|
||||
%define maybe() \
|
||||
%if %(test -n "%{?2}" && echo 1 || echo 0) \
|
||||
%* \
|
||||
%endif
|
||||
%global maybe() \
|
||||
%%if %%(test -n "%%{?2}" && echo 1 || echo 0) \
|
||||
%%* \
|
||||
%%endif
|
||||
|
||||
%define have_with() %(if echo %{with_flags} | grep -q %1; then echo 1; else echo 0; fi)
|
||||
%define have_service() %(if echo %{services} | grep -q %1; then echo 1; else echo 0; fi)
|
||||
%global have_with() %%(if echo %%{with_flags} | grep -q %%1; then echo 1; else echo 0; fi)
|
||||
%global have_service() %%(if echo %%{services} | grep -q %%1; then echo 1; else echo 0; fi)
|
||||
|
||||
%define daemon_reload \
|
||||
%if %{enable_systemd} \
|
||||
%global daemon_reload \
|
||||
%%if %%{enable_systemd} \
|
||||
systemctl daemon-reload > /dev/null 2>&1 || : \
|
||||
%endif \
|
||||
%%endif \
|
||||
: \
|
||||
%{nil}
|
||||
%%{nil}
|
||||
|
||||
%define enable(s:t:) \
|
||||
%if %{have_service %{-s*}} \
|
||||
%if %{enable_systemd} \
|
||||
%global enable(s:t:) \
|
||||
%%if %%{have_service %%{-s*}} \
|
||||
%%if %%{enable_systemd} \
|
||||
if [ $1 = 1 ]; then \
|
||||
systemctl preset lvm2-%{-s*}.%{-t*} > /dev/null 2>&1 || : \
|
||||
systemctl preset lvm2-%%{-s*}.%%{-t*} > /dev/null 2>&1 || : \
|
||||
fi \
|
||||
%else \
|
||||
/sbin/chkconfig --add lvm2-%{-s*} \
|
||||
%endif \
|
||||
%endif \
|
||||
%%else \
|
||||
/sbin/chkconfig --add lvm2-%%{-s*} \
|
||||
%%endif \
|
||||
%%endif \
|
||||
: \
|
||||
%{nil}
|
||||
%%{nil}
|
||||
|
||||
%define disable(s:t:) \
|
||||
%if %{have_service %{-s*}} \
|
||||
%if %{enable_systemd} \
|
||||
%global disable(s:t:) \
|
||||
%%if %%{have_service %%{-s*}} \
|
||||
%%if %%{enable_systemd} \
|
||||
if [ $1 = 0 ]; then \
|
||||
systemctl --no-reload disable lvm2-%{-s*}.%{-t*} > /dev/null 2>&1 || : \
|
||||
%if %{-t*} == socket \
|
||||
systemctl --no-reload disable lvm2-%{-s*}.service > /dev/null 2>&1 || : \
|
||||
%endif \
|
||||
systemctl stop lvm2-%{-s*}.%{-t*} > /dev/null 2>&1 || : \
|
||||
%if %{-t*} == socket \
|
||||
systemctl stop lvm2-%{-s*}.service > /dev/null 2>&1 || : \
|
||||
%endif \
|
||||
systemctl --no-reload disable lvm2-%%{-s*}.%%{-t*} > /dev/null 2>&1 || : \
|
||||
%%if %%{-t*} == socket \
|
||||
systemctl --no-reload disable lvm2-%%{-s*}.service > /dev/null 2>&1 || : \
|
||||
%%endif \
|
||||
systemctl stop lvm2-%%{-s*}.%%{-t*} > /dev/null 2>&1 || : \
|
||||
%%if %%{-t*} == socket \
|
||||
systemctl stop lvm2-%%{-s*}.service > /dev/null 2>&1 || : \
|
||||
%%endif \
|
||||
fi \
|
||||
%else \
|
||||
/sbin/chkconfig --del lvm2-%{-s*} \
|
||||
%endif \
|
||||
%endif \
|
||||
%%else \
|
||||
/sbin/chkconfig --del lvm2-%%{-s*} \
|
||||
%%endif \
|
||||
%%endif \
|
||||
: \
|
||||
%{nil}
|
||||
%%{nil}
|
||||
|
||||
%define try_restart(s:t:) \
|
||||
%if %{have_service %{-s*}} && %{enable_systemd} \
|
||||
%global try_restart(s:t:) \
|
||||
%%if %%{have_service %%{-s*}} && %%{enable_systemd} \
|
||||
if [ $1 = 1 ]; then \
|
||||
systemctl try-restart lvm2-%{-s*}.%{-t*} > /dev/null 2>&1 || : \
|
||||
systemctl try-restart lvm2-%%{-s*}.%%{-t*} > /dev/null 2>&1 || : \
|
||||
fi \
|
||||
%endif \
|
||||
%%endif \
|
||||
: \
|
||||
%{nil}
|
||||
%%{nil}
|
||||
|
@@ -176,13 +176,13 @@ fi
|
||||
%attr(644, -, -) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/lvm/lvm.conf
|
||||
%attr(644, -, -) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/lvm/lvmlocal.conf
|
||||
%dir %{_sysconfdir}/lvm/profile
|
||||
%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/lvm/profile/command_profile_template.profile
|
||||
%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/lvm/profile/metadata_profile_template.profile
|
||||
%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/lvm/profile/thin-generic.profile
|
||||
%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/lvm/profile/thin-performance.profile
|
||||
%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/lvm/profile/cache-mq.profile
|
||||
%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/lvm/profile/cache-smq.profile
|
||||
%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/lvm/profile/lvmdbusd.profile
|
||||
%{_sysconfdir}/lvm/profile/command_profile_template.profile
|
||||
%{_sysconfdir}/lvm/profile/metadata_profile_template.profile
|
||||
%{_sysconfdir}/lvm/profile/thin-generic.profile
|
||||
%{_sysconfdir}/lvm/profile/thin-performance.profile
|
||||
%{_sysconfdir}/lvm/profile/cache-mq.profile
|
||||
%{_sysconfdir}/lvm/profile/cache-smq.profile
|
||||
%{_sysconfdir}/lvm/profile/lvmdbusd.profile
|
||||
%dir %{_sysconfdir}/lvm/backup
|
||||
%dir %{_sysconfdir}/lvm/cache
|
||||
%dir %{_sysconfdir}/lvm/archive
|
||||
|
@@ -12,6 +12,7 @@
|
||||
%global enable_udev 1
|
||||
%global enable_systemd 1
|
||||
%global enable_cmirror 1
|
||||
# enable_lvmlockd is redefined in spec/build.inc, so are other :-/
|
||||
%global enable_lvmlockd 1
|
||||
%global enable_lvmetad 1
|
||||
%global enable_lvmpolld 1
|
||||
@@ -48,23 +49,28 @@
|
||||
%global req_udev udev >= 181-1
|
||||
|
||||
|
||||
%if %{fedora} >= 22 || %{rhel} >= 7
|
||||
%if %{fedora} >= 24 || %{rhel} >= 7
|
||||
%service lvmlockd 1
|
||||
%define sanlock_version 3.2.4-1
|
||||
%define enable_lockd_dlm 1
|
||||
%define enable_lockd_sanlock 1
|
||||
%global sanlock_version 3.3.0-1
|
||||
%global enable_lockd_dlm 1
|
||||
%global enable_lockd_sanlock 1
|
||||
%if %{rhel}
|
||||
%ifarch i686 x86_64 s390x
|
||||
%global buildreq_lockd_dlm dlm-devel >= %{dlm_version}
|
||||
%else
|
||||
%define enable_lockd_dlm 0
|
||||
%global enable_lockd_dlm 0
|
||||
%endif
|
||||
%ifarch x86_64 ppc64le ppc64 aarch64
|
||||
%global buildreq_lockd_sanlock sanlock-devel >= %{sanlock_version}
|
||||
%else
|
||||
%define enable_lockd_sanlock 0
|
||||
%global enable_lockd_sanlock 0
|
||||
%endif
|
||||
%endif
|
||||
%else
|
||||
%if %{fedora} >= 22
|
||||
%service lvmlockd 1
|
||||
%global enable_lockd_dlm 1
|
||||
%endif
|
||||
%endif
|
||||
|
||||
##############################################################
|
||||
@@ -140,7 +146,7 @@
|
||||
# same as FC 16 above, only with older udev
|
||||
|
||||
%if %{rhel} == 6
|
||||
%define req_udev udev >= 147-2
|
||||
%global req_udev udev >= 147-2
|
||||
%global req_dm_persistent device-mapper-persistent-data >= 0.1.4
|
||||
%endif
|
||||
|
||||
@@ -149,7 +155,7 @@
|
||||
# Do not reset Release to 1 unless both lvm2 and device-mapper
|
||||
# versions are increased together.
|
||||
|
||||
%define device_mapper_version 1.02.97
|
||||
%global device_mapper_version 1.02.97
|
||||
|
||||
Summary: Userland logical volume management tools
|
||||
Name: lvm2
|
||||
|
@@ -77,6 +77,9 @@ 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."
|
||||
@@ -144,6 +147,21 @@ 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)
|
||||
|
@@ -1376,6 +1376,15 @@ 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
|
||||
|
||||
run_types raid4 -i 2 "$dev1" "$dev2" "$dev3" "$dev4"
|
||||
aux have_raid4 && 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,6 +16,9 @@ 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
|
||||
@@ -78,22 +81,61 @@ aux wait_for_sync $vg $lv1
|
||||
# Clean up
|
||||
lvremove --yes $vg/$lv1
|
||||
|
||||
# Create 3-way raid0
|
||||
lvcreate -y -aey --type raid0 -i 3 -L 64M -n $lv1 $vg
|
||||
check lv_field $vg/$lv1 segtype "raid0"
|
||||
# Create 3-way striped
|
||||
lvcreate -y -aey --type striped -i 3 -L 64M -n $lv1 $vg
|
||||
check lv_field $vg/$lv1 segtype "striped"
|
||||
check lv_field $vg/$lv1 stripes 3
|
||||
echo y | mkfs -t ext4 /dev/mapper/$vg-$lv1
|
||||
fsck -fn /dev/mapper/$vg-$lv1
|
||||
|
||||
# Convert raid0 -> raid4
|
||||
# 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
|
||||
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"
|
||||
@@ -116,11 +158,24 @@ 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,8 +31,11 @@ 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 4 5 6; do
|
||||
for i in $levels; do
|
||||
lvcreate --type raid$i -i 3 -l 3 -n $lv1 $vg
|
||||
|
||||
if [ $i -eq 6 ]; then
|
||||
|
@@ -25,7 +25,8 @@ which "$FSCK" || skip
|
||||
#
|
||||
# Main
|
||||
#
|
||||
aux have_cache 1 5 0 || skip
|
||||
# older versions of cache target reported unreliably write failures
|
||||
aux have_cache 1 7 0 || skip
|
||||
|
||||
aux prepare_vg 4
|
||||
|
||||
|
@@ -53,7 +53,8 @@ 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"
|
||||
not lvconvert -y --repair $vg/$lv1
|
||||
# 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
|
||||
aux wait_for_sync $vg $lv1
|
||||
lvconvert -y --repair $vg/$lv1
|
||||
vgreduce --removemissing $vg
|
||||
|
@@ -56,7 +56,7 @@ fail lvcreate -l 1 --cachepool pool8 $vg
|
||||
|
||||
# no size specified
|
||||
invalid lvcreate --cachepool pool $vg 2>&1 | tee err
|
||||
# grep "specify either size or extents" err
|
||||
grep "specify either size or extents" err
|
||||
|
||||
# Check nothing has been created yet
|
||||
check vg_field $vg lv_count 0
|
||||
|
@@ -21,6 +21,9 @@ 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
|
||||
|
||||
@@ -53,7 +56,7 @@ check raid_leg_status $vg1 $lv1 "AA"
|
||||
lvremove -ff $vg1
|
||||
|
||||
# 750 TiB raid4/5
|
||||
for segtype in raid4 raid5; do
|
||||
for segtype in $segtypes; 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,17 +16,20 @@ 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 10 $(get first_extent_sector "$dev1")
|
||||
aux delay_dev "$dev1" 0 50 $(get first_extent_sector "$dev1")
|
||||
|
||||
# raid0/raid0_meta don't support resynchronization
|
||||
for r in raid0 raid0_meta
|
||||
do
|
||||
lvcreate --yes --type raid0 -i 3 -l 1 -n $lv1 $vg
|
||||
lvcreate --yes --type $r -i 3 -l 1 -n $lv1 $vg
|
||||
check raid_leg_status $vg $lv1 "AAA"
|
||||
lvremove --yes $vg/$lv1
|
||||
done
|
||||
@@ -43,8 +46,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 raid4 raid5
|
||||
do
|
||||
for r in $segtypes
|
||||
do
|
||||
# raid4/5 support resynchronization
|
||||
lvcreate --yes --type $r -i 3 -l 2 -n $lv1 $vg
|
||||
check raid_leg_status $vg $lv1 "aaaa"
|
||||
|
@@ -23,6 +23,9 @@ 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)
|
||||
|
||||
@@ -54,7 +57,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
|
||||
|
||||
@@ -64,7 +67,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,6 +24,28 @@ 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,6 +16,9 @@ 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)
|
||||
@@ -37,7 +40,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 4 5 6 ; do
|
||||
for i in $levels ; do
|
||||
lvcreate --type raid$i -i 3 -l 3 -n $lv2 $vg
|
||||
|
||||
test $deactivate && {
|
||||
@@ -59,7 +62,7 @@ done
|
||||
|
||||
# Bug 1005434
|
||||
# Ensure extend is contiguous
|
||||
lvcreate --type raid4 -l 2 -i 2 -n $lv1 $vg "$dev4" "$dev5" "$dev6"
|
||||
lvcreate --type raid5 -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"
|
||||
|
||||
|
@@ -40,13 +40,14 @@ snap_and_merge() {
|
||||
kill $SLEEP_PID
|
||||
|
||||
aux delay_dev "$dev1" 0 200 $(get first_extent_sector "$dev1"):
|
||||
lvchange --refresh $vg/$lv1
|
||||
lvchange --poll n --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
|
||||
@@ -56,7 +57,7 @@ snap_and_merge() {
|
||||
check lv_attr_bit state $vg/$lv2 "m"
|
||||
|
||||
# device OK and running in full speed
|
||||
aux enable_dev "$dev1" "$dev2"
|
||||
aux enable_dev "$dev2"
|
||||
|
||||
# reactivate so merge can finish
|
||||
lvchange -an $vg
|
||||
|
@@ -23,6 +23,7 @@ lvcreate -l 1 -n lv1 $vg "$dev1"
|
||||
invalid vgextend
|
||||
# --metadatacopies => use --pvmetadatacopies
|
||||
invalid vgextend --metadatacopies 3 $vg "$dev1" 2>&1 | tee out
|
||||
grep -- "use --pvmetadatacopies" out
|
||||
|
||||
# VG name should exist
|
||||
fail vgextend --restoremissing $vg-invalid "$dev1"
|
||||
|
@@ -76,7 +76,6 @@ SOURCES2 =\
|
||||
|
||||
TARGETS =\
|
||||
.commands \
|
||||
command-lines.h \
|
||||
liblvm2cmd.a \
|
||||
lvm
|
||||
|
||||
@@ -100,8 +99,7 @@ LIB_VERSION = $(LIB_VERSION_LVM)
|
||||
CLEAN_TARGETS = liblvm2cmd.$(LIB_SUFFIX) $(TARGETS_DM) \
|
||||
liblvm2cmd.$(LIB_SUFFIX).$(LIB_VERSION) lvm-static.o \
|
||||
liblvm2cmd-static.a dmsetup.static lvm.static \
|
||||
$(LDDEPS) .exported_symbols_generated \
|
||||
ccmd command-lines.h command-lines-count.h
|
||||
$(LDDEPS) .exported_symbols_generated
|
||||
|
||||
ifeq ("@CMDLIB@", "yes")
|
||||
TARGETS += liblvm2cmd.$(LIB_SUFFIX).$(LIB_VERSION)
|
||||
@@ -173,13 +171,6 @@ liblvm2cmd.$(LIB_SUFFIX).$(LIB_VERSION): liblvm2cmd.$(LIB_SUFFIX)
|
||||
$(CC) -E -P $(srcdir)/cmdnames.h 2> /dev/null | \
|
||||
egrep -v '^ *(|#.*|config|devtypes|dumpconfig|formats|fullreport|help|lastlog|lvpoll|pvdata|segtypes|systemid|tags|version) *$$' > .commands
|
||||
|
||||
ccmd: create-commands.c
|
||||
$(CC) create-commands.c -o ccmd
|
||||
|
||||
command-lines.h: ccmd
|
||||
./ccmd --output struct command-lines.in > command-lines.h
|
||||
./ccmd --output count command-lines.in > command-lines-count.h
|
||||
|
||||
ifneq ("$(CFLOW_CMD)", "")
|
||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
||||
-include $(top_builddir)/libdm/libdevmapper.cflow
|
||||
|
405
tools/args.h
405
tools/args.h
@@ -17,214 +17,215 @@
|
||||
* Put all long args that don't have a corresponding short option first.
|
||||
*/
|
||||
/* *INDENT-OFF* */
|
||||
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)
|
||||
arg(aligned_ARG, '\0', "aligned", 0, 0, 0)
|
||||
arg(alloc_ARG, '\0', "alloc", alloc_VAL, 0, 0)
|
||||
arg(atomic_ARG, '\0', "atomic", 0, 0, 0)
|
||||
arg(atversion_ARG, '\0', "atversion", string_VAL, 0, 0)
|
||||
arg(binary_ARG, '\0', "binary", 0, 0, 0)
|
||||
arg(bootloaderareasize_ARG, '\0', "bootloaderareasize", sizemb_VAL, 0, 0)
|
||||
arg(cache_long_ARG, '\0', "cache", 0, 0, 0)
|
||||
arg(cachemode_ARG, '\0', "cachemode", cachemode_VAL, 0, 0)
|
||||
arg(cachepool_ARG, '\0', "cachepool", lv_VAL, 0, 0)
|
||||
arg(commandprofile_ARG, '\0', "commandprofile", string_VAL, 0, 0)
|
||||
arg(config_ARG, '\0', "config", string_VAL, 0, 0)
|
||||
arg(configreport_ARG, '\0', "configreport", string_VAL, ARG_GROUPABLE, 1)
|
||||
arg(configtype_ARG, '\0', "typeconfig", string_VAL, 0, 0)
|
||||
arg(corelog_ARG, '\0', "corelog", 0, 0, 0)
|
||||
arg(dataalignment_ARG, '\0', "dataalignment", sizekb_VAL, 0, 0)
|
||||
arg(dataalignmentoffset_ARG, '\0', "dataalignmentoffset", sizekb_VAL, 0, 0)
|
||||
arg(deltag_ARG, '\0', "deltag", tag_VAL, ARG_GROUPABLE, 0)
|
||||
arg(detachprofile_ARG, '\0', "detachprofile", 0, 0, 0)
|
||||
arg(discards_ARG, '\0', "discards", discards_VAL, 0, 0)
|
||||
arg(driverloaded_ARG, '\0', "driverloaded", bool_VAL, 0, 0)
|
||||
arg(errorwhenfull_ARG, '\0', "errorwhenfull", bool_VAL, 0, 0)
|
||||
arg(force_long_ARG, '\0', "force", 0, ARG_COUNTABLE, 0)
|
||||
arg(foreign_ARG, '\0', "foreign", 0, 0, 0)
|
||||
arg(handlemissingpvs_ARG, '\0', "handlemissingpvs", 0, 0, 0)
|
||||
arg(ignoreadvanced_ARG, '\0', "ignoreadvanced", 0, 0, 0)
|
||||
arg(ignorelocal_ARG, '\0', "ignorelocal", 0, 0, 0)
|
||||
arg(ignorelockingfailure_ARG, '\0', "ignorelockingfailure", 0, 0, 0)
|
||||
arg(ignoremonitoring_ARG, '\0', "ignoremonitoring", 0, 0, 0)
|
||||
arg(ignoreskippedcluster_ARG, '\0', "ignoreskippedcluster", 0, 0, 0)
|
||||
arg(ignoreunsupported_ARG, '\0', "ignoreunsupported", 0, 0, 0)
|
||||
arg(labelsector_ARG, '\0', "labelsector", number_VAL, 0, 0)
|
||||
arg(lockopt_ARG, '\0', "lockopt", string_VAL, 0, 0)
|
||||
arg(lockstart_ARG, '\0', "lockstart", 0, 0, 0)
|
||||
arg(lockstop_ARG, '\0', "lockstop", 0, 0, 0)
|
||||
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(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)
|
||||
arg(metadataprofile_ARG, '\0', "metadataprofile", string_VAL, 0, 0)
|
||||
arg(metadatasize_ARG, '\0', "metadatasize", sizemb_VAL, 0, 0)
|
||||
arg(minor_ARG, '\0', "minor", number_VAL, ARG_GROUPABLE, 0)
|
||||
arg(minrecoveryrate_ARG, '\0', "minrecoveryrate", sizekb_VAL, 0, 0)
|
||||
arg(mirrorlog_ARG, '\0', "mirrorlog", mirrorlog_VAL, 0, 0)
|
||||
arg(mirrorsonly_ARG, '\0', "mirrorsonly", 0, 0, 0)
|
||||
arg(mknodes_ARG, '\0', "mknodes", 0, 0, 0)
|
||||
arg(monitor_ARG, '\0', "monitor", bool_VAL, 0, 0)
|
||||
arg(nameprefixes_ARG, '\0', "nameprefixes", 0, 0, 0)
|
||||
arg(noheadings_ARG, '\0', "noheadings", 0, 0, 0)
|
||||
arg(nohistory_ARG, '\0', "nohistory", 0, 0, 0)
|
||||
arg(nolocking_ARG, '\0', "nolocking", 0, 0, 0)
|
||||
arg(norestorefile_ARG, '\0', "norestorefile", 0, 0, 0)
|
||||
arg(nosuffix_ARG, '\0', "nosuffix", 0, 0, 0)
|
||||
arg(nosync_ARG, '\0', "nosync", 0, 0, 0)
|
||||
arg(notifydbus_ARG, '\0', "notifydbus", 0, 0, 0)
|
||||
arg(noudevsync_ARG, '\0', "noudevsync", 0, 0, 0)
|
||||
arg(originname_ARG, '\0', "originname", lv_VAL, 0, 0)
|
||||
arg(physicalvolumesize_ARG, '\0', "setphysicalvolumesize", sizemb_VAL, 0, 0)
|
||||
arg(poll_ARG, '\0', "poll", bool_VAL, 0, 0)
|
||||
arg(polloperation_ARG, '\0', "polloperation", string_VAL, 0, 0)
|
||||
arg(pooldatasize_ARG, '\0', "pooldatasize", sizemb_VAL, 0, 0)
|
||||
arg(poolmetadata_ARG, '\0', "poolmetadata", lv_VAL, 0, 0)
|
||||
arg(poolmetadatasize_ARG, '\0', "poolmetadatasize", sizemb_VAL, 0, 0)
|
||||
arg(poolmetadataspare_ARG, '\0', "poolmetadataspare", bool_VAL, 0, 0)
|
||||
arg(profile_ARG, '\0', "profile", string_VAL, 0, 0)
|
||||
arg(pvmetadatacopies_ARG, '\0', "pvmetadatacopies", pvmetadatacopies_VAL, 0, 0)
|
||||
arg(raidrebuild_ARG, '\0', "raidrebuild", string_VAL, ARG_GROUPABLE, 0)
|
||||
arg(raidmaxrecoveryrate_ARG, '\0', "raidmaxrecoveryrate", sizekb_VAL, 0, 0)
|
||||
arg(raidminrecoveryrate_ARG, '\0', "raidminrecoveryrate", sizekb_VAL, 0, 0)
|
||||
arg(raidsyncaction_ARG, '\0', "raidsyncaction", string_VAL, 0, 0)
|
||||
arg(raidwritebehind_ARG, '\0', "raidwritebehind", number_VAL, 0, 0)
|
||||
arg(raidwritemostly_ARG, '\0', "raidwritemostly", string_VAL, ARG_GROUPABLE, 0)
|
||||
arg(readonly_ARG, '\0', "readonly", 0, 0, 0)
|
||||
arg(refresh_ARG, '\0', "refresh", 0, 0, 0)
|
||||
arg(removemissing_ARG, '\0', "removemissing", 0, 0, 0)
|
||||
arg(rebuild_ARG, '\0', "rebuild", pv_VAL, ARG_GROUPABLE, 0)
|
||||
arg(repair_ARG, '\0', "repair", 0, 0, 0)
|
||||
arg(replace_ARG, '\0', "replace", pv_VAL, ARG_GROUPABLE, 0)
|
||||
arg(reportformat_ARG, '\0', "reportformat", string_VAL, 0, 0)
|
||||
arg(restorefile_ARG, '\0', "restorefile", string_VAL, 0, 0)
|
||||
arg(restoremissing_ARG, '\0', "restoremissing", 0, 0, 0)
|
||||
arg(resync_ARG, '\0', "resync", 0, 0, 0)
|
||||
arg(rows_ARG, '\0', "rows", 0, 0, 0)
|
||||
arg(segments_ARG, '\0', "segments", 0, 0, 0)
|
||||
arg(separator_ARG, '\0', "separator", string_VAL, 0, 0)
|
||||
arg(shared_ARG, '\0', "shared", 0, 0, 0)
|
||||
arg(sinceversion_ARG, '\0', "sinceversion", string_VAL, 0, 0)
|
||||
arg(split_ARG, '\0', "split", 0, 0, 0)
|
||||
arg(splitcache_ARG, '\0', "splitcache", 0, 0, 0)
|
||||
arg(splitmirrors_ARG, '\0', "splitmirrors", number_VAL, 0, 0)
|
||||
arg(splitsnapshot_ARG, '\0', "splitsnapshot", 0, 0, 0)
|
||||
arg(showdeprecated_ARG, '\0', "showdeprecated", 0, 0, 0)
|
||||
arg(showunsupported_ARG, '\0', "showunsupported", 0, 0, 0)
|
||||
arg(stripes_long_ARG, '\0', "stripes", number_VAL, 0, 0)
|
||||
arg(syncaction_ARG, '\0', "syncaction", string_VAL, 0, 0) /* FIXME Use custom VAL */
|
||||
arg(sysinit_ARG, '\0', "sysinit", 0, 0, 0)
|
||||
arg(systemid_ARG, '\0', "systemid", string_VAL, 0, 0)
|
||||
arg(thinpool_ARG, '\0', "thinpool", lv_VAL, 0, 0)
|
||||
arg(trackchanges_ARG, '\0', "trackchanges", 0, 0, 0)
|
||||
arg(trustcache_ARG, '\0', "trustcache", 0, 0, 0)
|
||||
arg(type_ARG, '\0', "type", segtype_VAL, 0, 0)
|
||||
arg(unbuffered_ARG, '\0', "unbuffered", 0, 0, 0)
|
||||
arg(uncache_ARG, '\0', "uncache", 0, 0, 0)
|
||||
arg(cachepolicy_ARG, '\0', "cachepolicy", string_VAL, 0, 0)
|
||||
arg(cachesettings_ARG, '\0', "cachesettings", string_VAL, ARG_GROUPABLE, 0)
|
||||
arg(unconfigured_ARG, '\0', "unconfigured", 0, 0, 0)
|
||||
arg(units_ARG, '\0', "units", units_VAL, 0, 0)
|
||||
arg(unquoted_ARG, '\0', "unquoted", 0, 0, 0)
|
||||
arg(usepolicies_ARG, '\0', "usepolicies", 0, 0, 0)
|
||||
arg(validate_ARG, '\0', "validate", 0, 0, 0)
|
||||
arg(version_ARG, '\0', "version", 0, 0, 0)
|
||||
arg(vgmetadatacopies_ARG, '\0', "vgmetadatacopies", vgmetadatacopies_VAL, 0, 0)
|
||||
arg(virtualoriginsize_ARG, '\0', "virtualoriginsize", sizemb_VAL, 0, 0)
|
||||
arg(withsummary_ARG, '\0', "withsummary", 0, 0, 0)
|
||||
arg(withcomments_ARG, '\0', "withcomments", 0, 0, 0)
|
||||
arg(withspaces_ARG, '\0', "withspaces", 0, 0, 0)
|
||||
arg(withversions_ARG, '\0', "withversions", 0, 0, 0)
|
||||
arg(writebehind_ARG, '\0', "writebehind", number_VAL, 0, 0)
|
||||
arg(writemostly_ARG, '\0', "writemostly", string_VAL, ARG_GROUPABLE, 0)
|
||||
arg(abort_ARG, '\0', "abort", NULL, 0, 0)
|
||||
arg(activationmode_ARG, '\0', "activationmode", string_arg, 0, 0)
|
||||
arg(addtag_ARG, '\0', "addtag", tag_arg, ARG_GROUPABLE, 0)
|
||||
arg(aligned_ARG, '\0', "aligned", NULL, 0, 0)
|
||||
arg(alloc_ARG, '\0', "alloc", alloc_arg, 0, 0)
|
||||
arg(atomic_ARG, '\0', "atomic", NULL, 0, 0)
|
||||
arg(atversion_ARG, '\0', "atversion", string_arg, 0, 0)
|
||||
arg(binary_ARG, '\0', "binary", NULL, 0, 0)
|
||||
arg(bootloaderareasize_ARG, '\0', "bootloaderareasize", size_mb_arg, 0, 0)
|
||||
arg(cache_long_ARG, '\0', "cache", NULL, 0, 0)
|
||||
arg(cachemode_ARG, '\0', "cachemode", cachemode_arg, 0, 0)
|
||||
arg(cachepool_ARG, '\0', "cachepool", string_arg, 0, 0)
|
||||
arg(commandprofile_ARG, '\0', "commandprofile", string_arg, 0, 0)
|
||||
arg(config_ARG, '\0', "config", string_arg, 0, 0)
|
||||
arg(configreport_ARG, '\0', "configreport", string_arg, ARG_GROUPABLE, 1)
|
||||
arg(configtype_ARG, '\0', "type", string_arg, 0, 0)
|
||||
arg(corelog_ARG, '\0', "corelog", NULL, 0, 0)
|
||||
arg(dataalignment_ARG, '\0', "dataalignment", size_kb_arg, 0, 0)
|
||||
arg(dataalignmentoffset_ARG, '\0', "dataalignmentoffset", size_kb_arg, 0, 0)
|
||||
arg(deltag_ARG, '\0', "deltag", tag_arg, ARG_GROUPABLE, 0)
|
||||
arg(detachprofile_ARG, '\0', "detachprofile", NULL, 0, 0)
|
||||
arg(discards_ARG, '\0', "discards", discards_arg, 0, 0)
|
||||
arg(driverloaded_ARG, '\0', "driverloaded", yes_no_arg, 0, 0)
|
||||
arg(errorwhenfull_ARG, '\0', "errorwhenfull", yes_no_arg, 0, 0)
|
||||
arg(force_long_ARG, '\0', "force", NULL, ARG_COUNTABLE, 0)
|
||||
arg(foreign_ARG, '\0', "foreign", NULL, 0, 0)
|
||||
arg(handlemissingpvs_ARG, '\0', "handlemissingpvs", NULL, 0, 0)
|
||||
arg(ignoreadvanced_ARG, '\0', "ignoreadvanced", NULL, 0, 0)
|
||||
arg(ignorelocal_ARG, '\0', "ignorelocal", NULL, 0, 0)
|
||||
arg(ignorelockingfailure_ARG, '\0', "ignorelockingfailure", NULL, 0, 0)
|
||||
arg(ignoremonitoring_ARG, '\0', "ignoremonitoring", NULL, 0, 0)
|
||||
arg(ignoreskippedcluster_ARG, '\0', "ignoreskippedcluster", NULL, 0, 0)
|
||||
arg(ignoreunsupported_ARG, '\0', "ignoreunsupported", NULL, 0, 0)
|
||||
arg(labelsector_ARG, '\0', "labelsector", int_arg, 0, 0)
|
||||
arg(lockopt_ARG, '\0', "lockopt", string_arg, 0, 0)
|
||||
arg(lockstart_ARG, '\0', "lockstart", NULL, 0, 0)
|
||||
arg(lockstop_ARG, '\0', "lockstop", NULL, 0, 0)
|
||||
arg(locktype_ARG, '\0', "locktype", locktype_arg, 0, 0)
|
||||
arg(logonly_ARG, '\0', "logonly", NULL, 0, 0)
|
||||
arg(maxrecoveryrate_ARG, '\0', "maxrecoveryrate", size_kb_arg, 0, 0)
|
||||
arg(merge_ARG, '\0', "merge", NULL, 0, 0)
|
||||
arg(mergedconfig_ARG, '\0', "mergedconfig", NULL, 0, 0)
|
||||
arg(metadatacopies_ARG, '\0', "metadatacopies", metadatacopies_arg, 0, 0)
|
||||
arg(metadataignore_ARG, '\0', "metadataignore", yes_no_arg, 0, 0)
|
||||
arg(metadataprofile_ARG, '\0', "metadataprofile", string_arg, 0, 0)
|
||||
arg(metadatasize_ARG, '\0', "metadatasize", size_mb_arg, 0, 0)
|
||||
arg(minor_ARG, '\0', "minor", int_arg, ARG_GROUPABLE, 0)
|
||||
arg(minrecoveryrate_ARG, '\0', "minrecoveryrate", size_kb_arg, 0, 0)
|
||||
arg(mirrorlog_ARG, '\0', "mirrorlog", mirrorlog_arg, 0, 0)
|
||||
arg(mirrorsonly_ARG, '\0', "mirrorsonly", NULL, 0, 0)
|
||||
arg(mknodes_ARG, '\0', "mknodes", NULL, 0, 0)
|
||||
arg(monitor_ARG, '\0', "monitor", yes_no_arg, 0, 0)
|
||||
arg(nameprefixes_ARG, '\0', "nameprefixes", NULL, 0, 0)
|
||||
arg(noheadings_ARG, '\0', "noheadings", NULL, 0, 0)
|
||||
arg(nohistory_ARG, '\0', "nohistory", NULL, 0, 0)
|
||||
arg(nolocking_ARG, '\0', "nolocking", NULL, 0, 0)
|
||||
arg(norestorefile_ARG, '\0', "norestorefile", NULL, 0, 0)
|
||||
arg(nosuffix_ARG, '\0', "nosuffix", NULL, 0, 0)
|
||||
arg(nosync_ARG, '\0', "nosync", NULL, 0, 0)
|
||||
arg(notifydbus_ARG, '\0', "notifydbus", NULL, 0, 0)
|
||||
arg(noudevsync_ARG, '\0', "noudevsync", NULL, 0, 0)
|
||||
arg(originname_ARG, '\0', "originname", string_arg, 0, 0)
|
||||
arg(physicalvolumesize_ARG, '\0', "setphysicalvolumesize", size_mb_arg, 0, 0)
|
||||
arg(poll_ARG, '\0', "poll", yes_no_arg, 0, 0)
|
||||
arg(polloperation_ARG, '\0', "polloperation", string_arg, 0, 0)
|
||||
arg(pooldatasize_ARG, '\0', "pooldatasize", size_mb_arg, 0, 0)
|
||||
arg(poolmetadata_ARG, '\0', "poolmetadata", string_arg, 0, 0)
|
||||
arg(poolmetadatasize_ARG, '\0', "poolmetadatasize", size_mb_arg, 0, 0)
|
||||
arg(poolmetadataspare_ARG, '\0', "poolmetadataspare", yes_no_arg, 0, 0)
|
||||
arg(profile_ARG, '\0', "profile", string_arg, 0, 0)
|
||||
arg(pvmetadatacopies_ARG, '\0', "pvmetadatacopies", int_arg, 0, 0)
|
||||
arg(raidrebuild_ARG, '\0', "raidrebuild", string_arg, ARG_GROUPABLE, 0)
|
||||
arg(raidmaxrecoveryrate_ARG, '\0', "raidmaxrecoveryrate", size_kb_arg, 0, 0)
|
||||
arg(raidminrecoveryrate_ARG, '\0', "raidminrecoveryrate", size_kb_arg, 0, 0)
|
||||
arg(raidsyncaction_ARG, '\0', "raidsyncaction", string_arg, 0, 0)
|
||||
arg(raidwritebehind_ARG, '\0', "raidwritebehind", int_arg, 0, 0)
|
||||
arg(raidwritemostly_ARG, '\0', "raidwritemostly", string_arg, ARG_GROUPABLE, 0)
|
||||
arg(readonly_ARG, '\0', "readonly", NULL, 0, 0)
|
||||
arg(refresh_ARG, '\0', "refresh", NULL, 0, 0)
|
||||
arg(removemissing_ARG, '\0', "removemissing", NULL, 0, 0)
|
||||
arg(rebuild_ARG, '\0', "rebuild", string_arg, ARG_GROUPABLE, 0)
|
||||
arg(repair_ARG, '\0', "repair", NULL, 0, 0)
|
||||
arg(replace_ARG, '\0', "replace", string_arg, ARG_GROUPABLE, 0)
|
||||
arg(reportformat_ARG, '\0', "reportformat", string_arg, 0, 0)
|
||||
arg(restorefile_ARG, '\0', "restorefile", string_arg, 0, 0)
|
||||
arg(restoremissing_ARG, '\0', "restoremissing", NULL, 0, 0)
|
||||
arg(resync_ARG, '\0', "resync", NULL, 0, 0)
|
||||
arg(rows_ARG, '\0', "rows", NULL, 0, 0)
|
||||
arg(segments_ARG, '\0', "segments", NULL, 0, 0)
|
||||
arg(separator_ARG, '\0', "separator", string_arg, 0, 0)
|
||||
arg(shared_ARG, '\0', "shared", NULL, 0, 0)
|
||||
arg(sinceversion_ARG, '\0', "sinceversion", string_arg, 0, 0)
|
||||
arg(split_ARG, '\0', "split", NULL, 0, 0)
|
||||
arg(splitcache_ARG, '\0', "splitcache", NULL, 0, 0)
|
||||
arg(splitmirrors_ARG, '\0', "splitmirrors", int_arg, 0, 0)
|
||||
arg(splitsnapshot_ARG, '\0', "splitsnapshot", NULL, 0, 0)
|
||||
arg(showdeprecated_ARG, '\0', "showdeprecated", NULL, 0, 0)
|
||||
arg(showunsupported_ARG, '\0', "showunsupported", NULL, 0, 0)
|
||||
arg(stripes_long_ARG, '\0', "stripes", int_arg, 0, 0)
|
||||
arg(syncaction_ARG, '\0', "syncaction", string_arg, 0, 0) /* FIXME Use custom validation fn */
|
||||
arg(sysinit_ARG, '\0', "sysinit", NULL, 0, 0)
|
||||
arg(systemid_ARG, '\0', "systemid", string_arg, 0, 0)
|
||||
arg(thinpool_ARG, '\0', "thinpool", string_arg, 0, 0)
|
||||
arg(trackchanges_ARG, '\0', "trackchanges", NULL, 0, 0)
|
||||
arg(trustcache_ARG, '\0', "trustcache", NULL, 0, 0)
|
||||
arg(type_ARG, '\0', "type", segtype_arg, 0, 0)
|
||||
arg(unbuffered_ARG, '\0', "unbuffered", NULL, 0, 0)
|
||||
arg(uncache_ARG, '\0', "uncache", NULL, 0, 0)
|
||||
arg(cachepolicy_ARG, '\0', "cachepolicy", string_arg, 0, 0)
|
||||
arg(cachesettings_ARG, '\0', "cachesettings", string_arg, ARG_GROUPABLE, 0)
|
||||
arg(unconfigured_ARG, '\0', "unconfigured", NULL, 0, 0)
|
||||
arg(units_ARG, '\0', "units", string_arg, 0, 0)
|
||||
arg(unquoted_ARG, '\0', "unquoted", NULL, 0, 0)
|
||||
arg(usepolicies_ARG, '\0', "usepolicies", NULL, 0, 0)
|
||||
arg(validate_ARG, '\0', "validate", NULL, 0, 0)
|
||||
arg(version_ARG, '\0', "version", NULL, 0, 0)
|
||||
arg(vgmetadatacopies_ARG, '\0', "vgmetadatacopies", metadatacopies_arg, 0, 0)
|
||||
arg(virtualoriginsize_ARG, '\0', "virtualoriginsize", size_mb_arg, 0, 0)
|
||||
arg(withsummary_ARG, '\0', "withsummary", NULL, 0, 0)
|
||||
arg(withcomments_ARG, '\0', "withcomments", NULL, 0, 0)
|
||||
arg(withspaces_ARG, '\0', "withspaces", NULL, 0, 0)
|
||||
arg(withversions_ARG, '\0', "withversions", NULL, 0, 0)
|
||||
arg(writebehind_ARG, '\0', "writebehind", int_arg, 0, 0)
|
||||
arg(writemostly_ARG, '\0', "writemostly", string_arg, ARG_GROUPABLE, 0)
|
||||
|
||||
/* Allow some variations */
|
||||
arg(allocation_ARG, '\0', "allocation", bool_VAL, 0, 0)
|
||||
arg(available_ARG, '\0', "available", activation_VAL, 0, 0)
|
||||
arg(resizable_ARG, '\0', "resizable", bool_VAL, 0, 0)
|
||||
arg(allocation_ARG, '\0', "allocation", yes_no_arg, 0, 0)
|
||||
arg(available_ARG, '\0', "available", activation_arg, 0, 0)
|
||||
arg(resizable_ARG, '\0', "resizable", yes_no_arg, 0, 0)
|
||||
|
||||
/*
|
||||
* ... and now the short args.
|
||||
*/
|
||||
arg(activate_ARG, 'a', "activate", activation_VAL, 0, 0)
|
||||
arg(all_ARG, 'a', "all", 0, 0, 0)
|
||||
arg(autobackup_ARG, 'A', "autobackup", bool_VAL, 0, 0)
|
||||
arg(activevolumegroups_ARG, 'A', "activevolumegroups", 0, 0, 0)
|
||||
arg(background_ARG, 'b', "background", 0, 0, 0)
|
||||
arg(backgroundfork_ARG, 'b', "background", 0, 0, 0)
|
||||
arg(basevgname_ARG, 'n', "basevgname", string_VAL, 0, 0)
|
||||
arg(blockdevice_ARG, 'b', "blockdevice", 0, 0, 0)
|
||||
arg(chunksize_ARG, 'c', "chunksize", sizekb_VAL, 0, 0)
|
||||
arg(clustered_ARG, 'c', "clustered", bool_VAL, 0, 0)
|
||||
arg(colon_ARG, 'c', "colon", 0, 0, 0)
|
||||
arg(columns_ARG, 'C', "columns", 0, 0, 0)
|
||||
arg(contiguous_ARG, 'C', "contiguous", bool_VAL, 0, 0)
|
||||
arg(debug_ARG, 'd', "debug", 0, ARG_COUNTABLE, 0)
|
||||
arg(exported_ARG, 'e', "exported", 0, 0, 0)
|
||||
arg(physicalextent_ARG, 'E', "physicalextent", 0, 0, 0)
|
||||
arg(file_ARG, 'f', "file", string_VAL, 0, 0)
|
||||
arg(force_ARG, 'f', "force", 0, ARG_COUNTABLE, 0)
|
||||
arg(full_ARG, 'f', "full", 0, 0, 0)
|
||||
arg(help_ARG, 'h', "help", 0, ARG_COUNTABLE, 0)
|
||||
arg(cache_ARG, 'H', "cache", 0, 0, 0)
|
||||
arg(history_ARG, 'H', "history", 0, 0, 0)
|
||||
arg(help2_ARG, '?', "", 0, 0, 0)
|
||||
arg(import_ARG, 'i', "import", 0, 0, 0)
|
||||
arg(interval_ARG, 'i', "interval", number_VAL, 0, 0)
|
||||
arg(iop_version_ARG, 'i', "iop_version", 0, 0, 0)
|
||||
arg(stripes_ARG, 'i', "stripes", number_VAL, 0, 0)
|
||||
arg(stripesize_ARG, 'I', "stripesize", sizekb_VAL, 0, 0)
|
||||
arg(logicalvolume_ARG, 'l', "logicalvolume", number_VAL, 0, 0)
|
||||
arg(maxlogicalvolumes_ARG, 'l', "maxlogicalvolumes", number_VAL, 0, 0)
|
||||
arg(extents_ARG, 'l', "extents", numsignedper_VAL, 0, 0)
|
||||
arg(list_ARG, 'l', "list", 0, 0, 0)
|
||||
arg(lvmpartition_ARG, 'l', "lvmpartition", 0, 0, 0)
|
||||
arg(size_ARG, 'L', "size", sizemb_VAL, 0, 0)
|
||||
arg(persistent_ARG, 'M', "persistent", bool_VAL, 0, 0)
|
||||
arg(major_ARG, 'j', "major", number_VAL, ARG_GROUPABLE, 0)
|
||||
arg(setactivationskip_ARG, 'k', "setactivationskip", bool_VAL, 0, 0)
|
||||
arg(ignoreactivationskip_ARG, 'K', "ignoreactivationskip", 0, 0, 0)
|
||||
arg(maps_ARG, 'm', "maps", 0, 0, 0)
|
||||
arg(mirrors_ARG, 'm', "mirrors", numsigned_VAL, 0, 0)
|
||||
arg(metadatatype_ARG, 'M', "metadatatype", metadatatype_VAL, 0, 0)
|
||||
arg(name_ARG, 'n', "name", string_VAL, 0, 0)
|
||||
arg(nofsck_ARG, 'n', "nofsck", 0, 0, 0)
|
||||
arg(novolumegroup_ARG, 'n', "novolumegroup", 0, 0, 0)
|
||||
arg(oldpath_ARG, 'n', "oldpath", 0, 0, 0)
|
||||
arg(options_ARG, 'o', "options", string_VAL, ARG_GROUPABLE, 0)
|
||||
arg(sort_ARG, 'O', "sort", string_VAL, ARG_GROUPABLE, 0)
|
||||
arg(maxphysicalvolumes_ARG, 'p', "maxphysicalvolumes", number_VAL, 0, 0)
|
||||
arg(permission_ARG, 'p', "permission", permission_VAL, 0, 0)
|
||||
arg(partial_ARG, 'P', "partial", 0, 0, 0)
|
||||
arg(physicalvolume_ARG, 'P', "physicalvolume", 0, 0, 0)
|
||||
arg(quiet_ARG, 'q', "quiet", 0, ARG_COUNTABLE, 0)
|
||||
arg(readahead_ARG, 'r', "readahead", readahead_VAL, 0, 0)
|
||||
arg(resizefs_ARG, 'r', "resizefs", 0, 0, 0)
|
||||
arg(reset_ARG, 'R', "reset", 0, 0, 0)
|
||||
arg(regionsize_ARG, 'R', "regionsize", sizemb_VAL, 0, 0)
|
||||
arg(physicalextentsize_ARG, 's', "physicalextentsize", sizemb_VAL, 0, 0)
|
||||
arg(snapshot_ARG, 's', "snapshot", 0, 0, 0)
|
||||
arg(short_ARG, 's', "short", 0, 0, 0)
|
||||
arg(stdin_ARG, 's', "stdin", 0, 0, 0)
|
||||
arg(select_ARG, 'S', "select", string_VAL, ARG_GROUPABLE, 0)
|
||||
arg(test_ARG, 't', "test", 0, 0, 0)
|
||||
arg(thin_ARG, 'T', "thin", 0, 0, 0)
|
||||
arg(uuid_ARG, 'u', "uuid", 0, 0, 0)
|
||||
arg(uuidstr_ARG, 'u', "uuid", string_VAL, 0, 0)
|
||||
arg(uuidlist_ARG, 'U', "uuidlist", 0, 0, 0)
|
||||
arg(verbose_ARG, 'v', "verbose", 0, ARG_COUNTABLE, 0)
|
||||
arg(volumegroup_ARG, 'V', "volumegroup", 0, 0, 0)
|
||||
arg(virtualsize_ARG, 'V', "virtualsize", sizemb_VAL, 0, 0)
|
||||
arg(wipesignatures_ARG, 'W', "wipesignatures", bool_VAL, 0, 0)
|
||||
arg(allocatable_ARG, 'x', "allocatable", bool_VAL, 0, 0)
|
||||
arg(resizeable_ARG, 'x', "resizeable", bool_VAL, 0, 0)
|
||||
arg(yes_ARG, 'y', "yes", 0, 0, 0)
|
||||
arg(zero_ARG, 'Z', "zero", bool_VAL, 0, 0)
|
||||
arg(activate_ARG, 'a', "activate", activation_arg, 0, 0)
|
||||
arg(all_ARG, 'a', "all", NULL, 0, 0)
|
||||
arg(autobackup_ARG, 'A', "autobackup", yes_no_arg, 0, 0)
|
||||
arg(activevolumegroups_ARG, 'A', "activevolumegroups", NULL, 0, 0)
|
||||
arg(background_ARG, 'b', "background", NULL, 0, 0)
|
||||
arg(backgroundfork_ARG, 'b', "background", NULL, 0, 0)
|
||||
arg(basevgname_ARG, 'n', "basevgname", string_arg, 0, 0)
|
||||
arg(blockdevice_ARG, 'b', "blockdevice", NULL, 0, 0)
|
||||
arg(chunksize_ARG, 'c', "chunksize", size_kb_arg, 0, 0)
|
||||
arg(clustered_ARG, 'c', "clustered", yes_no_arg, 0, 0)
|
||||
arg(colon_ARG, 'c', "colon", NULL, 0, 0)
|
||||
arg(columns_ARG, 'C', "columns", NULL, 0, 0)
|
||||
arg(contiguous_ARG, 'C', "contiguous", yes_no_arg, 0, 0)
|
||||
arg(debug_ARG, 'd', "debug", NULL, ARG_COUNTABLE, 0)
|
||||
arg(exported_ARG, 'e', "exported", NULL, 0, 0)
|
||||
arg(physicalextent_ARG, 'E', "physicalextent", NULL, 0, 0)
|
||||
arg(file_ARG, 'f', "file", string_arg, 0, 0)
|
||||
arg(force_ARG, 'f', "force", NULL, ARG_COUNTABLE, 0)
|
||||
arg(full_ARG, 'f', "full", NULL, 0, 0)
|
||||
arg(help_ARG, 'h', "help", NULL, 0, 0)
|
||||
arg(cache_ARG, 'H', "cache", NULL, 0, 0)
|
||||
arg(history_ARG, 'H', "history", NULL, 0, 0)
|
||||
arg(help2_ARG, '?', "", NULL, 0, 0)
|
||||
arg(import_ARG, 'i', "import", NULL, 0, 0)
|
||||
arg(interval_ARG, 'i', "interval", int_arg, 0, 0)
|
||||
arg(iop_version_ARG, 'i', "iop_version", NULL, 0, 0)
|
||||
arg(stripes_ARG, 'i', "stripes", int_arg, 0, 0)
|
||||
arg(stripesize_ARG, 'I', "stripesize", size_kb_arg, 0, 0)
|
||||
arg(logicalvolume_ARG, 'l', "logicalvolume", int_arg, 0, 0)
|
||||
arg(maxlogicalvolumes_ARG, 'l', "maxlogicalvolumes", int_arg, 0, 0)
|
||||
arg(extents_ARG, 'l', "extents", int_arg_with_sign_and_percent, 0, 0)
|
||||
arg(list_ARG, 'l', "list", NULL, 0, 0)
|
||||
arg(lvmpartition_ARG, 'l', "lvmpartition", NULL, 0, 0)
|
||||
arg(logicalextent_ARG, 'L', "logicalextent", int_arg_with_sign, 0, 0)
|
||||
arg(size_ARG, 'L', "size", size_mb_arg, 0, 0)
|
||||
arg(persistent_ARG, 'M', "persistent", yes_no_arg, 0, 0)
|
||||
arg(major_ARG, 'j', "major", int_arg, ARG_GROUPABLE, 0)
|
||||
arg(setactivationskip_ARG, 'k', "setactivationskip", yes_no_arg, 0, 0)
|
||||
arg(ignoreactivationskip_ARG, 'K', "ignoreactivationskip", NULL, 0, 0)
|
||||
arg(maps_ARG, 'm', "maps", NULL, 0, 0)
|
||||
arg(mirrors_ARG, 'm', "mirrors", int_arg_with_sign, 0, 0)
|
||||
arg(metadatatype_ARG, 'M', "metadatatype", metadatatype_arg, 0, 0)
|
||||
arg(name_ARG, 'n', "name", string_arg, 0, 0)
|
||||
arg(nofsck_ARG, 'n', "nofsck", NULL, 0, 0)
|
||||
arg(novolumegroup_ARG, 'n', "novolumegroup", NULL, 0, 0)
|
||||
arg(oldpath_ARG, 'n', "oldpath", NULL, 0, 0)
|
||||
arg(options_ARG, 'o', "options", string_arg, ARG_GROUPABLE, 0)
|
||||
arg(sort_ARG, 'O', "sort", string_arg, ARG_GROUPABLE, 0)
|
||||
arg(maxphysicalvolumes_ARG, 'p', "maxphysicalvolumes", int_arg, 0, 0)
|
||||
arg(permission_ARG, 'p', "permission", permission_arg, 0, 0)
|
||||
arg(partial_ARG, 'P', "partial", NULL, 0, 0)
|
||||
arg(physicalvolume_ARG, 'P', "physicalvolume", NULL, 0, 0)
|
||||
arg(quiet_ARG, 'q', "quiet", NULL, ARG_COUNTABLE, 0)
|
||||
arg(readahead_ARG, 'r', "readahead", readahead_arg, 0, 0)
|
||||
arg(resizefs_ARG, 'r', "resizefs", NULL, 0, 0)
|
||||
arg(reset_ARG, 'R', "reset", NULL, 0, 0)
|
||||
arg(regionsize_ARG, 'R', "regionsize", size_mb_arg, 0, 0)
|
||||
arg(physicalextentsize_ARG, 's', "physicalextentsize", size_mb_arg, 0, 0)
|
||||
arg(snapshot_ARG, 's', "snapshot", NULL, 0, 0)
|
||||
arg(short_ARG, 's', "short", NULL, 0, 0)
|
||||
arg(stdin_ARG, 's', "stdin", NULL, 0, 0)
|
||||
arg(select_ARG, 'S', "select", string_arg, ARG_GROUPABLE, 0)
|
||||
arg(test_ARG, 't', "test", NULL, 0, 0)
|
||||
arg(thin_ARG, 'T', "thin", NULL, 0, 0)
|
||||
arg(uuid_ARG, 'u', "uuid", NULL, 0, 0)
|
||||
arg(uuidstr_ARG, 'u', "uuid", string_arg, 0, 0)
|
||||
arg(uuidlist_ARG, 'U', "uuidlist", NULL, 0, 0)
|
||||
arg(verbose_ARG, 'v', "verbose", NULL, ARG_COUNTABLE, 0)
|
||||
arg(volumegroup_ARG, 'V', "volumegroup", NULL, 0, 0)
|
||||
arg(virtualsize_ARG, 'V', "virtualsize", size_mb_arg, 0, 0)
|
||||
arg(wipesignatures_ARG, 'W', "wipesignatures", yes_no_arg, 0, 0)
|
||||
arg(allocatable_ARG, 'x', "allocatable", yes_no_arg, 0, 0)
|
||||
arg(resizeable_ARG, 'x', "resizeable", yes_no_arg, 0, 0)
|
||||
arg(yes_ARG, 'y', "yes", NULL, 0, 0)
|
||||
arg(zero_ARG, 'Z', "zero", yes_no_arg, 0, 0)
|
||||
|
||||
/* this should always be last */
|
||||
arg(ARG_COUNT, '-', "", 0, 0, 0)
|
||||
arg(ARG_COUNT, '-', "", NULL, 0, 0)
|
||||
/* *INDENT-ON* */
|
||||
|
File diff suppressed because it is too large
Load Diff
170
tools/command.h
170
tools/command.h
@@ -1,170 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _LVM_COMMAND_H
|
||||
#define _LVM_COMMAND_H
|
||||
|
||||
struct cmd_context;
|
||||
|
||||
/* old per-command-name function */
|
||||
typedef int (*command_fn) (struct cmd_context *cmd, int argc, char **argv);
|
||||
|
||||
/* new per-command-line-id functions */
|
||||
typedef int (*command_line_fn) (struct cmd_context *cmd, int argc, char **argv);
|
||||
|
||||
struct command_function {
|
||||
int command_line_enum;
|
||||
command_line_fn fn;
|
||||
};
|
||||
|
||||
struct command_name {
|
||||
const char *name;
|
||||
const char *desc; /* general command description from commands.h */
|
||||
unsigned int flags;
|
||||
|
||||
/* union of {required,optional}_opt_args for all commands with this name */
|
||||
int valid_args[ARG_COUNT];
|
||||
int num_args;
|
||||
};
|
||||
|
||||
/*
|
||||
* Command defintion
|
||||
*
|
||||
* A command is defined in terms of a command name,
|
||||
* required options (+args), optional options (+args),
|
||||
* required positional args, optional positional args.
|
||||
*
|
||||
* A positional arg always has non-zero pos_arg.def.types.
|
||||
* The first positional arg has pos_arg.pos of 1.
|
||||
*/
|
||||
|
||||
/* arg_def flags */
|
||||
#define ARG_DEF_FLAG_NEW 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;
|
||||
}
|
||||
|
||||
static inline uint64_t val_enum_to_bit(int val_enum)
|
||||
{
|
||||
return 1 << val_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 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_ */
|
||||
};
|
||||
|
||||
/* Description of an option and the value that follows it. */
|
||||
|
||||
struct opt_arg {
|
||||
int opt; /* option, e.g. foo_ARG */
|
||||
struct arg_def def; /* defines accepted values */
|
||||
};
|
||||
|
||||
/* Description of a position and the value that exists there. */
|
||||
|
||||
struct pos_arg {
|
||||
int pos; /* position, e.g. first is 1 */
|
||||
struct arg_def def; /* defines accepted values */
|
||||
};
|
||||
|
||||
/*
|
||||
* CMD_RO_ARGS needs to accomodate a list of options,
|
||||
* of which one is required after which the rest are
|
||||
* optional.
|
||||
*/
|
||||
#define CMD_RO_ARGS 64 /* required opt args */
|
||||
#define CMD_OO_ARGS 150 /* optional opt args */
|
||||
#define CMD_RP_ARGS 8 /* required positional args */
|
||||
#define CMD_OP_ARGS 8 /* optional positional args */
|
||||
|
||||
/*
|
||||
* one or more from required_opt_args is required,
|
||||
* then the rest are optional.
|
||||
*/
|
||||
#define CMD_FLAG_ONE_REQUIRED_OPT 1
|
||||
#define CMD_FLAG_SECONDARY_SYNTAX 2
|
||||
|
||||
/* a register of the lvm commands */
|
||||
struct command {
|
||||
const char *name;
|
||||
const char *desc; /* specific command description from command-lines.h */
|
||||
const char *usage; /* excludes common options like --help, --debug */
|
||||
const char *usage_common; /* includes commmon options like --help, --debug */
|
||||
const char *command_line_id;
|
||||
int command_line_enum; /* <command_line_id>_CMD */
|
||||
|
||||
struct command_name *cname;
|
||||
|
||||
command_fn fn; /* old style */
|
||||
struct command_function *functions; /* new style */
|
||||
|
||||
unsigned int flags; /* copied from command_name.flags from commands.h */
|
||||
|
||||
unsigned int cmd_flags; /* CMD_FLAG_ */
|
||||
|
||||
/* definitions of opt/pos args */
|
||||
|
||||
/* required args following an --opt */
|
||||
struct opt_arg required_opt_args[CMD_RO_ARGS];
|
||||
|
||||
/* optional args following an --opt */
|
||||
struct opt_arg optional_opt_args[CMD_OO_ARGS];
|
||||
|
||||
/* required positional args */
|
||||
struct pos_arg required_pos_args[CMD_RP_ARGS];
|
||||
|
||||
/* optional positional args */
|
||||
struct pos_arg optional_pos_args[CMD_OP_ARGS];
|
||||
|
||||
int ro_count;
|
||||
int oo_count;
|
||||
int rp_count;
|
||||
int op_count;
|
||||
|
||||
/* used for processing current position */
|
||||
int pos_count;
|
||||
};
|
||||
|
||||
#endif
|
1428
tools/commands.h
1428
tools/commands.h
File diff suppressed because it is too large
Load Diff
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("This operation will destroy all semaphores %s%.0d%swith keys "
|
||||
log_warn("WARNING: 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,6 +2707,9 @@ 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)
|
||||
{
|
||||
@@ -2724,12 +2727,14 @@ static int _build_whole_deptree(const struct command *cmd)
|
||||
|
||||
static int _display_tree(CMD_ARGS)
|
||||
{
|
||||
if (!_build_whole_deptree(cmd))
|
||||
return_0;
|
||||
int r;
|
||||
|
||||
_display_tree_walk_children(dm_tree_find_node(_dtree, 0, 0), 0);
|
||||
r = _build_whole_deptree(cmd);
|
||||
|
||||
return 1;
|
||||
if (_dtree)
|
||||
_display_tree_walk_children(dm_tree_find_node(_dtree, 0, 0), 0);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4471,9 +4476,14 @@ static int _report_init(const struct command *cmd, const char *subcommand)
|
||||
selection, NULL, NULL)))
|
||||
goto_out;
|
||||
|
||||
if ((_report_type & DR_TREE) && cmd && !_build_whole_deptree(cmd)) {
|
||||
err("Internal device dependency tree creation failed.");
|
||||
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 (!_switches[INTERVAL_ARG])
|
||||
@@ -4484,8 +4494,6 @@ 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);
|
||||
@@ -5270,6 +5278,8 @@ 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;
|
||||
|
||||
@@ -5313,7 +5323,7 @@ static int _stats_delete(CMD_ARGS)
|
||||
log_error("Could not delete statistics region");
|
||||
goto out;
|
||||
}
|
||||
log_info("Deleted statistics region " FMTu64 ".\n", region_id);
|
||||
log_info("Deleted statistics region " FMTu64 ".", region_id);
|
||||
}
|
||||
|
||||
r = 1;
|
||||
@@ -6782,8 +6792,15 @@ unknown:
|
||||
argc--, argv++;
|
||||
}
|
||||
|
||||
if (_switches[COLS_ARG] && !_report_init(cmd, subcommand))
|
||||
goto_out;
|
||||
/* Default to success */
|
||||
ret = 0;
|
||||
|
||||
if (_switches[COLS_ARG]) {
|
||||
if (!_report_init(cmd, subcommand))
|
||||
ret = 1;
|
||||
if (ret || !_report)
|
||||
goto_out;
|
||||
}
|
||||
|
||||
if (_switches[COUNT_ARG])
|
||||
_count = ((uint32_t)_int_args[COUNT_ARG]) ? : UINT32_MAX;
|
||||
@@ -6795,14 +6812,17 @@ unknown:
|
||||
&_disp_units);
|
||||
if (!_disp_factor) {
|
||||
log_error("Invalid --units argument.");
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Start interval timer. */
|
||||
if (_count > 1)
|
||||
if (!_start_timer())
|
||||
if (!_start_timer()) {
|
||||
ret = 1;
|
||||
goto_out;
|
||||
}
|
||||
|
||||
doit:
|
||||
multiple_devices = (cmd->repeatable_cmd && argc != 1 &&
|
||||
@@ -6819,18 +6839,19 @@ doit:
|
||||
if (_count > 1 && r) {
|
||||
printf("\n");
|
||||
/* wait for --interval and update timestamps */
|
||||
if (!_do_report_wait())
|
||||
if (!_do_report_wait()) {
|
||||
ret = 1;
|
||||
goto_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!r)
|
||||
if (!r) {
|
||||
ret = 1;
|
||||
goto_out;
|
||||
}
|
||||
} while (--_count);
|
||||
|
||||
/* Success */
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
if (_report)
|
||||
dm_report_free(_report);
|
||||
@@ -6843,5 +6864,5 @@ out:
|
||||
if (_initial_timestamp)
|
||||
dm_timestamp_destroy(_initial_timestamp);
|
||||
|
||||
return ret;
|
||||
return (_switches[HELP_ARG] || _switches[VERSION_ARG]) ? 0 : ret;
|
||||
}
|
||||
|
283
tools/lvchange.c
283
tools/lvchange.c
@@ -1436,286 +1436,3 @@ int lvchange(struct cmd_context *cmd, int argc, char **argv)
|
||||
update ? READ_FOR_UPDATE : 0, NULL,
|
||||
&_lvchange_single);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Check if the status of the LV allows running lvchange.
|
||||
*
|
||||
* 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;
|
||||
|
||||
/* 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
|
||||
* (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.
|
||||
*/
|
||||
if (!lockd_lv(cmd, lv, "ex", 0)) {
|
||||
stack;
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
for (i = 0; i < cmd->command->ro_count; i++) {
|
||||
opt_enum = cmd->command->required_opt_args[i].opt;
|
||||
|
||||
if (!arg_is_set(cmd, opt_enum))
|
||||
continue;
|
||||
|
||||
if (!archive(lv->vg))
|
||||
return_ECMD_FAILED;
|
||||
|
||||
docmds++;
|
||||
|
||||
switch (opt_enum) {
|
||||
case permission_ARG:
|
||||
doit += _lvchange_permission(cmd, lv);
|
||||
break;
|
||||
|
||||
case alloc_ARG:
|
||||
case contiguous_ARG:
|
||||
doit += _lvchange_alloc(cmd, lv);
|
||||
break;
|
||||
|
||||
case errorwhenfull_ARG:
|
||||
doit += _lvchange_errorwhenfull(cmd, lv);
|
||||
break;
|
||||
|
||||
case readahead_ARG:
|
||||
doit += _lvchange_readahead(cmd, lv);
|
||||
break;
|
||||
|
||||
case persistent_ARG:
|
||||
doit += _lvchange_persistent(cmd, lv);
|
||||
break;
|
||||
|
||||
case discards_ARG:
|
||||
case zero_ARG:
|
||||
doit += _lvchange_pool_update(cmd, lv);
|
||||
break;
|
||||
|
||||
case addtag_ARG:
|
||||
case deltag_ARG:
|
||||
doit += _lvchange_tag(cmd, lv, opt_enum);
|
||||
break;
|
||||
|
||||
case writemostly_ARG:
|
||||
case writebehind_ARG:
|
||||
doit += _lvchange_writemostly(lv);
|
||||
break;
|
||||
|
||||
case minrecoveryrate_ARG:
|
||||
case maxrecoveryrate_ARG:
|
||||
doit += _lvchange_recovery_rate(lv);
|
||||
break;
|
||||
|
||||
case profile_ARG:
|
||||
case metadataprofile_ARG:
|
||||
case detachprofile_ARG:
|
||||
doit += _lvchange_profile(lv);
|
||||
break;
|
||||
|
||||
case setactivationskip_ARG:
|
||||
doit += _lvchange_activation_skip(lv);
|
||||
break;
|
||||
|
||||
case cachemode_ARG:
|
||||
case cachepolicy_ARG:
|
||||
case cachesettings_ARG:
|
||||
doit += _lvchange_cache(cmd, lv);
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error(INTERNAL_ERROR "Failed to check for option %s",
|
||||
arg_long_option_name(i));
|
||||
}
|
||||
|
||||
if (doit)
|
||||
log_print_unless_silent("Logical volume %s changed.", display_lvname(lv));
|
||||
|
||||
if (doit != docmds)
|
||||
return_ECMD_FAILED;
|
||||
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
|
||||
int lvchange_properties_cmd(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
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,
|
||||
struct logical_volume *lv,
|
||||
struct processing_handle *handle)
|
||||
{
|
||||
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 */
|
||||
if (lv_is_cow(lv) && lv_is_virtual_origin(origin = origin_from_cow(lv)))
|
||||
lv = origin;
|
||||
|
||||
if (lv_is_cow(lv)) {
|
||||
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 --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;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_lvchange_activate(cmd, lv))
|
||||
return_ECMD_FAILED;
|
||||
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
cmd->include_active_foreign_vgs = 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;
|
||||
|
||||
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))
|
||||
return_ECMD_FAILED;
|
||||
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
ret = process_each_lv(cmd, argc, argv, NULL, NULL, 0, handle, _lvchange_refresh_single);
|
||||
|
||||
destroy_processing_handle(cmd, handle);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@@ -37,19 +37,72 @@
|
||||
* deprecated. (The same is still needed for --merge.)
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
/* Merge:
|
||||
* If merge_snapshot is also set:
|
||||
* merge thin snapshot LV into its origin
|
||||
* merge old snapshot COW into its origin
|
||||
* or if merge_mirror is also set
|
||||
* merge LV previously split from mirror back into mirror
|
||||
*/
|
||||
CONV_MERGE = 1,
|
||||
|
||||
/* Split:
|
||||
* For a snapshot, split it apart into COW and origin for future recombination
|
||||
* For a cached LV, split it apart into the cached LV and its pool
|
||||
* For a mirrored or raid LV, split mirror into two mirrors, optionally tracking
|
||||
* future changes to the main mirror to allow future recombination.
|
||||
*/
|
||||
CONV_SPLIT = 2,
|
||||
CONV_SPLIT_SNAPSHOT = 3,
|
||||
CONV_SPLIT_CACHE = 4,
|
||||
CONV_SPLIT_MIRRORS = 5,
|
||||
|
||||
/* Start to cache an LV */
|
||||
CONV_CACHE = 6,
|
||||
|
||||
/* Destroy the cache attached to a cached LV */
|
||||
CONV_UNCACHE = 7,
|
||||
|
||||
/* Reconstruct a snapshot from its origin and COW */
|
||||
CONV_SNAPSHOT = 8,
|
||||
|
||||
/* Replace devices in a raid LV with alternatives */
|
||||
CONV_REPLACE = 9,
|
||||
|
||||
/* Repair a mirror, raid or thin LV */
|
||||
CONV_REPAIR = 10,
|
||||
|
||||
/* Convert normal LV into one in a thin pool */
|
||||
CONV_THIN = 11,
|
||||
|
||||
/* Every other segment type or mirror log conversion we haven't separated out */
|
||||
CONV_OTHER = 12,
|
||||
} conversion_type_t;
|
||||
|
||||
struct lvconvert_params {
|
||||
/* Exactly one of these 12 command categories is determined */
|
||||
int merge; /* Either merge_snapshot or merge_mirror is also set */
|
||||
int cache;
|
||||
int keep_mimages; /* --splitmirrors */
|
||||
int repair;
|
||||
int replace;
|
||||
int snapshot;
|
||||
int split;
|
||||
int splitcache;
|
||||
int splitsnapshot;
|
||||
int thin;
|
||||
int uncache;
|
||||
int merge; /* 1 */
|
||||
int split; /* 2 */
|
||||
int splitsnapshot; /* 3 */
|
||||
int splitcache; /* 4 */
|
||||
int keep_mimages; /* 5 */ /* --splitmirrors */
|
||||
int cache; /* 6 */
|
||||
int uncache; /* 7 */
|
||||
int snapshot; /* 8 */
|
||||
int replace; /* 9 */
|
||||
int repair; /* 10 */
|
||||
int thin; /* 11 */
|
||||
/* other */ /* 12 */
|
||||
|
||||
/* FIXME Eliminate all cases where more than one of the above are set then use conv_type instead */
|
||||
conversion_type_t conv_type;
|
||||
|
||||
int merge_snapshot; /* CONV_MERGE is set */
|
||||
int merge_mirror; /* CONV_MERGE is set */
|
||||
|
||||
int track_changes; /* CONV_SPLIT_MIRRORS is set */
|
||||
|
||||
int corelog; /* Equivalent to --mirrorlog core */
|
||||
int mirrorlog; /* Only one of corelog and mirrorlog may be set */
|
||||
|
||||
@@ -59,11 +112,6 @@ struct lvconvert_params {
|
||||
|
||||
const struct segment_type *segtype; /* Holds what segment type you will get */
|
||||
|
||||
int merge_snapshot; /* merge is also set */
|
||||
int merge_mirror; /* merge is also set */
|
||||
|
||||
int track_changes; /* keep_mimages is also set (--splitmirrors) */
|
||||
|
||||
int poolmetadataspare;
|
||||
int force;
|
||||
int yes;
|
||||
@@ -124,6 +172,15 @@ struct convert_poll_id_list {
|
||||
unsigned is_merging_origin_thin:1;
|
||||
};
|
||||
|
||||
/* FIXME Temporary function until the enum replaces the separate variables */
|
||||
static void _set_conv_type(struct lvconvert_params *lp, int conv_type)
|
||||
{
|
||||
if (lp->conv_type != CONV_OTHER)
|
||||
log_error(INTERNAL_ERROR "Changing conv_type from %d to %d.", lp->conv_type, conv_type);
|
||||
|
||||
lp->conv_type = conv_type;
|
||||
}
|
||||
|
||||
static int _lvconvert_validate_names(struct lvconvert_params *lp)
|
||||
{
|
||||
unsigned i, j;
|
||||
@@ -472,23 +529,18 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
|
||||
-1))
|
||||
return_0;
|
||||
lp->merge = 1;
|
||||
}
|
||||
|
||||
/* If --repair, check for incompatible args. */
|
||||
if (arg_is_set(cmd, repair_ARG)) {
|
||||
_set_conv_type(lp, CONV_MERGE);
|
||||
} else if (arg_is_set(cmd, repair_ARG)) {
|
||||
if (arg_outside_list_is_set(cmd, "cannot be used with --repair",
|
||||
repair_ARG,
|
||||
alloc_ARG, usepolicies_ARG,
|
||||
background_ARG, interval_ARG,
|
||||
force_ARG, noudevsync_ARG, test_ARG,
|
||||
-1))
|
||||
return_0;
|
||||
lp->repair = 1;
|
||||
}
|
||||
|
||||
if (arg_is_set(cmd, replace_ARG))
|
||||
lp->replace = 1;
|
||||
|
||||
if (arg_is_set(cmd, split_ARG)) {
|
||||
_set_conv_type(lp, CONV_REPAIR);
|
||||
} else if (arg_is_set(cmd, split_ARG)) {
|
||||
if (arg_outside_list_is_set(cmd, "cannot be used with --split",
|
||||
split_ARG,
|
||||
name_ARG,
|
||||
@@ -496,40 +548,40 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
|
||||
-1))
|
||||
return_0;
|
||||
lp->split = 1;
|
||||
}
|
||||
|
||||
if (arg_is_set(cmd, splitcache_ARG)) {
|
||||
_set_conv_type(lp, CONV_SPLIT);
|
||||
} else if (arg_is_set(cmd, splitcache_ARG)) {
|
||||
if (arg_outside_list_is_set(cmd, "cannot be used with --splitcache",
|
||||
splitcache_ARG,
|
||||
force_ARG, noudevsync_ARG, test_ARG,
|
||||
-1))
|
||||
return_0;
|
||||
lp->splitcache = 1;
|
||||
}
|
||||
|
||||
if (arg_is_set(cmd, splitsnapshot_ARG)) {
|
||||
_set_conv_type(lp, CONV_SPLIT_CACHE);
|
||||
} else if (arg_is_set(cmd, splitsnapshot_ARG)) {
|
||||
if (arg_outside_list_is_set(cmd, "cannot be used with --splitsnapshot",
|
||||
splitsnapshot_ARG,
|
||||
force_ARG, noudevsync_ARG, test_ARG,
|
||||
-1))
|
||||
return_0;
|
||||
lp->splitsnapshot = 1;
|
||||
}
|
||||
|
||||
if (arg_is_set(cmd, trackchanges_ARG))
|
||||
lp->track_changes = 1;
|
||||
|
||||
if (arg_is_set(cmd, uncache_ARG)) {
|
||||
_set_conv_type(lp, CONV_SPLIT_SNAPSHOT);
|
||||
} else if (arg_is_set(cmd, uncache_ARG)) {
|
||||
if (arg_outside_list_is_set(cmd, "cannot be used with --uncache",
|
||||
uncache_ARG,
|
||||
force_ARG, noudevsync_ARG, test_ARG,
|
||||
-1))
|
||||
return_0;
|
||||
lp->uncache = 1;
|
||||
_set_conv_type(lp, CONV_UNCACHE);
|
||||
} else if (arg_is_set(cmd, replace_ARG)) {
|
||||
lp->replace = 1;
|
||||
_set_conv_type(lp, CONV_REPLACE);
|
||||
}
|
||||
|
||||
if (arg_is_set(cmd, cache_ARG))
|
||||
if (arg_is_set(cmd, cache_ARG)) {
|
||||
lp->cache = 1;
|
||||
_set_conv_type(lp, CONV_CACHE);
|
||||
}
|
||||
|
||||
if (!strcmp(lp->type_str, SEG_TYPE_NAME_CACHE))
|
||||
lp->cache = 1;
|
||||
@@ -541,8 +593,10 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
|
||||
lp->type_str = SEG_TYPE_NAME_CACHE;
|
||||
}
|
||||
|
||||
if (arg_is_set(cmd, thin_ARG))
|
||||
if (arg_is_set(cmd, thin_ARG)) {
|
||||
lp->thin = 1;
|
||||
_set_conv_type(lp, CONV_THIN);
|
||||
}
|
||||
|
||||
if (!strcmp(lp->type_str, SEG_TYPE_NAME_THIN))
|
||||
lp->thin = 1;
|
||||
@@ -554,6 +608,9 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
|
||||
lp->type_str = SEG_TYPE_NAME_THIN;
|
||||
}
|
||||
|
||||
if (arg_is_set(cmd, trackchanges_ARG))
|
||||
lp->track_changes = 1;
|
||||
|
||||
if (!_read_pool_params(cmd, &argc, &argv, lp))
|
||||
return_0;
|
||||
|
||||
@@ -563,6 +620,7 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
|
||||
return 0;
|
||||
}
|
||||
lp->snapshot = 1;
|
||||
_set_conv_type(lp, CONV_SNAPSHOT);
|
||||
}
|
||||
|
||||
if (lp->split) {
|
||||
@@ -588,6 +646,7 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
|
||||
|
||||
lp->lv_split_name = arg_str_value(cmd, name_ARG, NULL);
|
||||
lp->keep_mimages = 1;
|
||||
_set_conv_type(lp, CONV_SPLIT_MIRRORS);
|
||||
lp->mirrors = arg_uint_value(cmd, splitmirrors_ARG, 0);
|
||||
lp->mirrors_sign = SIGN_MINUS;
|
||||
} else {
|
||||
@@ -642,6 +701,7 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Final checking of each case:
|
||||
* lp->merge
|
||||
@@ -658,23 +718,18 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
|
||||
* --type mirror|raid lp->mirrorlog lp->corelog
|
||||
* --type raid0|striped
|
||||
*/
|
||||
if (lp->merge) /* Snapshot or mirror merge */
|
||||
;
|
||||
else if (lp->splitsnapshot) /* Destroy snapshot retaining cow as separate LV */
|
||||
;
|
||||
else if (lp->splitcache)
|
||||
;
|
||||
else if (lp->split)
|
||||
;
|
||||
else if (lp->uncache)
|
||||
;
|
||||
else if (lp->cache)
|
||||
;
|
||||
else if (lp->thin)
|
||||
;
|
||||
else if (lp->keep_mimages) /* --splitmirrors */
|
||||
;
|
||||
else if (lp->snapshot) { /* Snapshot creation from pre-existing cow */
|
||||
switch(lp->conv_type) {
|
||||
case CONV_MERGE: /* Snapshot or mirror merge */
|
||||
case CONV_SPLIT:
|
||||
case CONV_SPLIT_CACHE:
|
||||
case CONV_SPLIT_MIRRORS:
|
||||
case CONV_SPLIT_SNAPSHOT: /* Destroy snapshot retaining cow as separate LV */
|
||||
case CONV_CACHE:
|
||||
case CONV_UNCACHE:
|
||||
case CONV_THIN:
|
||||
case CONV_REPAIR:
|
||||
break;
|
||||
case CONV_SNAPSHOT: /* Snapshot creation from pre-existing cow */
|
||||
if (!argc) {
|
||||
log_error("Please provide logical volume path for snapshot origin.");
|
||||
return 0;
|
||||
@@ -708,8 +763,9 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
|
||||
log_verbose("Setting chunk size to %s.", display_size(cmd, lp->chunk_size));
|
||||
|
||||
lp->type_str = SEG_TYPE_NAME_SNAPSHOT;
|
||||
break;
|
||||
|
||||
} else if (lp->replace) { /* RAID device replacement */
|
||||
case CONV_REPLACE: /* RAID device replacement */
|
||||
lp->replace_pv_count = arg_count(cmd, replace_ARG);
|
||||
lp->replace_pvs = dm_pool_alloc(cmd->mem, sizeof(char *) * lp->replace_pv_count);
|
||||
if (!lp->replace_pvs)
|
||||
@@ -729,72 +785,73 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
|
||||
tmp_str)))
|
||||
return_0;
|
||||
}
|
||||
} else if (lp->repair)
|
||||
;
|
||||
else if (_mirror_or_raid_type_requested(cmd, lp->type_str) ||
|
||||
lp->mirrorlog || lp->corelog) { /* Mirrors (and some RAID functions) */
|
||||
if (arg_is_set(cmd, chunksize_ARG)) {
|
||||
log_error("--chunksize is only available with snapshots or pools.");
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
if (arg_is_set(cmd, zero_ARG)) {
|
||||
log_error("--zero is only available with snapshots or thin pools.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* --regionsize is only valid if converting an LV into a mirror.
|
||||
* Checked when we know the state of the LV being converted.
|
||||
*/
|
||||
if (arg_is_set(cmd, regionsize_ARG)) {
|
||||
if (arg_sign_value(cmd, regionsize_ARG, SIGN_NONE) ==
|
||||
SIGN_MINUS) {
|
||||
log_error("Negative regionsize is invalid.");
|
||||
case CONV_OTHER:
|
||||
if (_mirror_or_raid_type_requested(cmd, lp->type_str) ||
|
||||
lp->mirrorlog || lp->corelog) { /* Mirrors (and some RAID functions) */
|
||||
if (arg_is_set(cmd, chunksize_ARG)) {
|
||||
log_error("--chunksize is only available with snapshots or pools.");
|
||||
return 0;
|
||||
}
|
||||
lp->region_size = arg_uint_value(cmd, regionsize_ARG, 0);
|
||||
} else {
|
||||
region_size = get_default_region_size(cmd);
|
||||
if (region_size < 0) {
|
||||
log_error("Negative regionsize in "
|
||||
"configuration file is invalid.");
|
||||
|
||||
if (arg_is_set(cmd, zero_ARG)) {
|
||||
log_error("--zero is only available with snapshots or thin pools.");
|
||||
return 0;
|
||||
}
|
||||
lp->region_size = region_size;
|
||||
}
|
||||
|
||||
if (lp->region_size % (pagesize >> SECTOR_SHIFT)) {
|
||||
log_error("Region size (%" PRIu32 ") must be "
|
||||
"a multiple of machine memory "
|
||||
"page size (%d).",
|
||||
lp->region_size, pagesize >> SECTOR_SHIFT);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* --regionsize is only valid if converting an LV into a mirror.
|
||||
* Checked when we know the state of the LV being converted.
|
||||
*/
|
||||
if (arg_is_set(cmd, regionsize_ARG)) {
|
||||
if (arg_sign_value(cmd, regionsize_ARG, SIGN_NONE) ==
|
||||
SIGN_MINUS) {
|
||||
log_error("Negative regionsize is invalid.");
|
||||
return 0;
|
||||
}
|
||||
lp->region_size = arg_uint_value(cmd, regionsize_ARG, 0);
|
||||
} else {
|
||||
region_size = get_default_region_size(cmd);
|
||||
if (region_size < 0) {
|
||||
log_error("Negative regionsize in "
|
||||
"configuration file is invalid.");
|
||||
return 0;
|
||||
}
|
||||
lp->region_size = region_size;
|
||||
}
|
||||
|
||||
if (!is_power_of_2(lp->region_size)) {
|
||||
log_error("Region size (%" PRIu32
|
||||
") must be a power of 2.", lp->region_size);
|
||||
return 0;
|
||||
}
|
||||
if (lp->region_size % (pagesize >> SECTOR_SHIFT)) {
|
||||
log_error("Region size (%" PRIu32 ") must be "
|
||||
"a multiple of machine memory "
|
||||
"page size (%d).",
|
||||
lp->region_size, pagesize >> SECTOR_SHIFT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lp->region_size) {
|
||||
log_error("Non-zero region size must be supplied.");
|
||||
return 0;
|
||||
}
|
||||
if (!is_power_of_2(lp->region_size)) {
|
||||
log_error("Region size (%" PRIu32
|
||||
") must be a power of 2.", lp->region_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME man page says in one place that --type and --mirrors can't be mixed */
|
||||
if (lp->mirrors_supplied && !lp->mirrors)
|
||||
/* down-converting to linear/stripe? */
|
||||
lp->type_str = SEG_TYPE_NAME_STRIPED;
|
||||
if (!lp->region_size) {
|
||||
log_error("Non-zero region size must be supplied.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
} else if (_raid0_type_requested(lp->type_str) || _striped_type_requested(lp->type_str)) { /* striped or linear or raid0 */
|
||||
if (arg_from_list_is_set(cmd, "cannot be used with --type raid0 or --type striped or --type linear",
|
||||
chunksize_ARG, corelog_ARG, mirrors_ARG, mirrorlog_ARG, regionsize_ARG, zero_ARG,
|
||||
-1))
|
||||
return_0;
|
||||
/* FIXME man page says in one place that --type and --mirrors can't be mixed */
|
||||
if (lp->mirrors_supplied && !lp->mirrors)
|
||||
/* down-converting to linear/stripe? */
|
||||
lp->type_str = SEG_TYPE_NAME_STRIPED;
|
||||
|
||||
} /* else segtype will default to current type */
|
||||
} else if (_raid0_type_requested(lp->type_str) || _striped_type_requested(lp->type_str)) { /* striped or linear or raid0 */
|
||||
if (arg_from_list_is_set(cmd, "cannot be used with --type raid0 or --type striped or --type linear",
|
||||
chunksize_ARG, corelog_ARG, mirrors_ARG, mirrorlog_ARG, regionsize_ARG, zero_ARG,
|
||||
-1))
|
||||
return_0;
|
||||
} /* else segtype will default to current type */
|
||||
}
|
||||
|
||||
lp->force = arg_count(cmd, force_ARG);
|
||||
lp->yes = arg_count(cmd, yes_ARG);
|
||||
@@ -1828,6 +1885,25 @@ static void _lvconvert_raid_repair_ask(struct cmd_context *cmd,
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for dm-raid target supporting raid4 conversion properly. */
|
||||
static int _raid4_conversion_supported(struct logical_volume *lv, struct lvconvert_params *lp)
|
||||
{
|
||||
int ret = 1;
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
|
||||
if (seg_is_raid4(seg))
|
||||
ret = raid4_is_supported(lv->vg->cmd, seg->segtype);
|
||||
else if (segtype_is_raid4(lp->segtype))
|
||||
ret = raid4_is_supported(lv->vg->cmd, lp->segtype);
|
||||
|
||||
if (ret)
|
||||
return 1;
|
||||
|
||||
log_error("Cannot convert %s LV %s to %s.",
|
||||
lvseg_name(seg), display_lvname(lv), lp->segtype->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *lp)
|
||||
{
|
||||
int replace = 0, image_count = 0;
|
||||
@@ -1944,13 +2020,24 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
|
||||
|
||||
if ((seg_is_linear(seg) || seg_is_striped(seg) || seg_is_mirrored(seg) || lv_is_raid(lv)) &&
|
||||
(lp->type_str && lp->type_str[0])) {
|
||||
/* Activation is required later which precludes existing unsupported raid0 segment */
|
||||
if (segtype_is_any_raid0(lp->segtype) &&
|
||||
/* Activation is required later which precludes existing supported raid0 segment */
|
||||
if ((seg_is_any_raid0(seg) || segtype_is_any_raid0(lp->segtype)) &&
|
||||
!(lp->target_attr & RAID_FEATURE_RAID0)) {
|
||||
log_error("RAID module does not support RAID0.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Activation is required later which precludes existing supported raid4 segment */
|
||||
if (!_raid4_conversion_supported(lv, lp))
|
||||
return 0;
|
||||
|
||||
/* Activation is required later which precludes existing supported raid10 segment */
|
||||
if ((seg_is_raid10(seg) || segtype_is_raid10(lp->segtype)) &&
|
||||
!(lp->target_attr & RAID_FEATURE_RAID10)) {
|
||||
log_error("RAID module does not support RAID10.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!arg_is_set(cmd, stripes_long_ARG))
|
||||
lp->stripes = 0;
|
||||
|
||||
@@ -1964,7 +2051,7 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
|
||||
}
|
||||
|
||||
if (lp->replace)
|
||||
return lv_raid_replace(lv, lp->replace_pvh, lp->pvh);
|
||||
return lv_raid_replace(lv, lp->force, lp->replace_pvh, lp->pvh);
|
||||
|
||||
if (lp->repair) {
|
||||
if (!lv_is_active_exclusive_locally(lv_lock_holder(lv))) {
|
||||
@@ -1987,7 +2074,7 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
|
||||
if (!(failed_pvs = _failed_pv_list(lv->vg)))
|
||||
return_0;
|
||||
|
||||
if (!lv_raid_replace(lv, failed_pvs, lp->pvh)) {
|
||||
if (!lv_raid_replace(lv, lp->force, failed_pvs, lp->pvh)) {
|
||||
log_error("Failed to replace faulty devices in %s.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
@@ -2008,6 +2095,9 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
|
||||
|
||||
try_new_takeover_or_reshape:
|
||||
|
||||
if (!_raid4_conversion_supported(lv, lp))
|
||||
return 0;
|
||||
|
||||
/* FIXME This needs changing globally. */
|
||||
if (!arg_is_set(cmd, stripes_long_ARG))
|
||||
lp->stripes = 0;
|
||||
@@ -4660,6 +4750,7 @@ int lvconvert(struct cmd_context * cmd, int argc, char **argv)
|
||||
int poll_ret, ret;
|
||||
struct convert_poll_id_list *idl;
|
||||
struct lvconvert_params lp = {
|
||||
.conv_type = CONV_OTHER,
|
||||
.target_attr = ~0,
|
||||
.idls = DM_LIST_HEAD_INIT(lp.idls),
|
||||
};
|
||||
|
@@ -1054,6 +1054,12 @@ 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;
|
||||
|
32
tools/lvm.c
32
tools/lvm.c
@@ -45,9 +45,9 @@ static char *_list_cmds(const char *text, int state)
|
||||
len = strlen(text);
|
||||
}
|
||||
|
||||
while (i < _cmdline->num_command_names)
|
||||
if (!strncmp(text, _cmdline->command_names[i++].name, len))
|
||||
return strdup(_cmdline->command_names[i - 1].name);
|
||||
while (i < _cmdline->num_commands)
|
||||
if (!strncmp(text, _cmdline->commands[i++].name, len))
|
||||
return strdup(_cmdline->commands[i - 1].name);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -57,7 +57,7 @@ static char *_list_args(const char *text, int state)
|
||||
{
|
||||
static int match_no = 0;
|
||||
static size_t len = 0;
|
||||
static struct command_name *cname;
|
||||
static struct command *com;
|
||||
|
||||
/* Initialise if this is a new completion attempt */
|
||||
if (!state) {
|
||||
@@ -65,40 +65,40 @@ static char *_list_args(const char *text, int state)
|
||||
int j;
|
||||
|
||||
match_no = 0;
|
||||
cname = NULL;
|
||||
com = NULL;
|
||||
len = strlen(text);
|
||||
|
||||
/* Find start of first word in line buffer */
|
||||
while (isspace(*s))
|
||||
s++;
|
||||
|
||||
/* Look for word in list of command names */
|
||||
for (j = 0; j < _cmdline->num_command_names; j++) {
|
||||
/* Look for word in list of commands */
|
||||
for (j = 0; j < _cmdline->num_commands; j++) {
|
||||
const char *p;
|
||||
char *q = s;
|
||||
|
||||
p = _cmdline->command_names[j].name;
|
||||
p = _cmdline->commands[j].name;
|
||||
while (*p == *q) {
|
||||
p++;
|
||||
q++;
|
||||
}
|
||||
if ((!*p) && *q == ' ') {
|
||||
cname = _cmdline->command_names + j;
|
||||
com = _cmdline->commands + j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!cname)
|
||||
if (!com)
|
||||
return NULL;
|
||||
|
||||
/* Short form arguments */
|
||||
if (len < 3) {
|
||||
while (match_no < cname->num_args) {
|
||||
while (match_no < com->num_args) {
|
||||
char s[3];
|
||||
char c;
|
||||
if (!(c = (_cmdline->arg_props +
|
||||
cname->valid_args[match_no++])->short_arg))
|
||||
com->valid_args[match_no++])->short_arg))
|
||||
continue;
|
||||
|
||||
sprintf(s, "-%c", c);
|
||||
@@ -108,13 +108,13 @@ static char *_list_args(const char *text, int state)
|
||||
}
|
||||
|
||||
/* Long form arguments */
|
||||
if (match_no < cname->num_args)
|
||||
match_no = cname->num_args;
|
||||
if (match_no < com->num_args)
|
||||
match_no = com->num_args;
|
||||
|
||||
while (match_no - cname->num_args < cname->num_args) {
|
||||
while (match_no - com->num_args < com->num_args) {
|
||||
const char *l;
|
||||
l = (_cmdline->arg_props +
|
||||
cname->valid_args[match_no++ - cname->num_args])->long_arg;
|
||||
com->valid_args[match_no++ - com->num_args])->long_arg;
|
||||
if (*(l + 2) && !strncmp(text, l, len))
|
||||
return strdup(l);
|
||||
}
|
||||
|
@@ -19,11 +19,10 @@
|
||||
struct cmd_context;
|
||||
|
||||
struct cmdline_context {
|
||||
struct arg_props *arg_props;
|
||||
struct command *commands;
|
||||
int num_commands;
|
||||
struct command_name *command_names;
|
||||
int num_command_names;
|
||||
struct arg_props *arg_props;
|
||||
struct command *commands;
|
||||
int num_commands;
|
||||
int commands_size;
|
||||
};
|
||||
|
||||
int lvm2_main(int argc, char **argv);
|
||||
|
@@ -30,12 +30,12 @@ void *cmdlib_lvm2_init(unsigned static_compile)
|
||||
{
|
||||
struct cmd_context *cmd;
|
||||
|
||||
lvm_register_commands();
|
||||
|
||||
init_is_static(static_compile);
|
||||
if (!(cmd = init_lvm(1, 1)))
|
||||
return NULL;
|
||||
|
||||
lvm_register_commands();
|
||||
|
||||
return (void *) cmd;
|
||||
}
|
||||
|
||||
|
1260
tools/lvmcmdline.c
1260
tools/lvmcmdline.c
File diff suppressed because it is too large
Load Diff
@@ -194,6 +194,9 @@ 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;
|
||||
|
||||
|
@@ -801,7 +801,10 @@ int vgcreate_params_set_from_args(struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (arg_is_set(cmd, vgmetadatacopies_ARG))
|
||||
if (arg_is_set(cmd, metadatacopies_ARG))
|
||||
vp_new->vgmetadatacopies = arg_int_value(cmd, metadatacopies_ARG,
|
||||
DEFAULT_VGMETADATACOPIES);
|
||||
else if (arg_is_set(cmd, vgmetadatacopies_ARG))
|
||||
vp_new->vgmetadatacopies = arg_int_value(cmd, vgmetadatacopies_ARG,
|
||||
DEFAULT_VGMETADATACOPIES);
|
||||
else
|
||||
@@ -2347,12 +2350,8 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
struct dm_str_list *sl;
|
||||
struct dm_list final_lvs;
|
||||
struct lv_list *final_lvl;
|
||||
struct dm_list found_arg_lvnames;
|
||||
struct glv_list *glvl, *tglvl;
|
||||
int do_report_ret_code = 1;
|
||||
uint32_t lv_types;
|
||||
struct logical_volume *lv;
|
||||
struct lv_segment *seg;
|
||||
|
||||
log_set_report_object_type(LOG_REPORT_OBJECT_TYPE_LV);
|
||||
|
||||
@@ -2361,7 +2360,6 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
stack;
|
||||
|
||||
dm_list_init(&final_lvs);
|
||||
dm_list_init(&found_arg_lvnames);
|
||||
|
||||
if (!vg_check_status(vg, EXPORTED_VG)) {
|
||||
ret_max = ECMD_FAILED;
|
||||
@@ -2455,7 +2453,6 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
if (lvargs_supplied && str_list_match_item(arg_lvnames, lvl->lv->name)) {
|
||||
/* Remove LV from list of unprocessed LV names */
|
||||
str_list_del(arg_lvnames, lvl->lv->name);
|
||||
str_list_add(cmd->mem, &found_arg_lvnames, lvl->lv->name);
|
||||
process_lv = 1;
|
||||
}
|
||||
|
||||
@@ -2503,68 +2500,6 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
if (lv_is_removed(lvl->lv))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* 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 ((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) {
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
log_very_verbose("Processing LV %s in VG %s.", lvl->lv->name, vg->name);
|
||||
|
||||
ret = process_single_lv(cmd, lvl->lv, handle);
|
||||
@@ -4001,6 +3936,11 @@ int pvcreate_params_from_args(struct cmd_context *cmd, struct pvcreate_params *p
|
||||
if (pp->pva.pvmetadatacopies < 0)
|
||||
pp->pva.pvmetadatacopies = find_config_tree_int(cmd, metadata_pvmetadatacopies_CFG, NULL);
|
||||
|
||||
if (pp->pva.pvmetadatacopies > 2) {
|
||||
log_error("Metadatacopies may only be 0, 1 or 2");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pp->pva.ba_size = arg_uint64_value(cmd, bootloaderareasize_ARG, pp->pva.ba_size);
|
||||
|
||||
return 1;
|
||||
|
@@ -50,27 +50,20 @@
|
||||
#define CMD_LEN 256
|
||||
#define MAX_ARGS 64
|
||||
|
||||
/* define the enums for the values accepted by command line --options */
|
||||
enum {
|
||||
#define val(a, b, c, d) a ,
|
||||
#include "vals.h"
|
||||
#undef val
|
||||
};
|
||||
/* command functions */
|
||||
typedef int (*command_fn) (struct cmd_context * cmd, int argc, char **argv);
|
||||
|
||||
/* define the enums for the command line --options */
|
||||
#define xx(a, b...) int a(struct cmd_context *cmd, int argc, char **argv);
|
||||
#include "commands.h"
|
||||
#undef xx
|
||||
|
||||
/* define the enums for the command line switches */
|
||||
enum {
|
||||
#define arg(a, b, c, d, e, f) a ,
|
||||
#include "args.h"
|
||||
#undef arg
|
||||
};
|
||||
|
||||
/* command functions */
|
||||
#define xx(a, b...) int a(struct cmd_context *cmd, int argc, char **argv);
|
||||
#include "commands.h"
|
||||
#undef xx
|
||||
|
||||
#include "command.h"
|
||||
|
||||
#define ARG_COUNTABLE 0x00000001 /* E.g. -vvvv */
|
||||
#define ARG_GROUPABLE 0x00000002 /* E.g. --addtag */
|
||||
|
||||
@@ -86,13 +79,13 @@ struct arg_values {
|
||||
/* void *ptr; // Currently not used. */
|
||||
};
|
||||
|
||||
/* a global table of possible --option's */
|
||||
/* a global table of possible arguments */
|
||||
struct arg_props {
|
||||
int arg_enum; /* foo_ARG from args.h */
|
||||
const char short_arg;
|
||||
char _padding[7];
|
||||
const char *long_arg;
|
||||
int val_enum; /* foo_VAL from vals.h */
|
||||
|
||||
int (*fn) (struct cmd_context *cmd, struct arg_values *av);
|
||||
uint32_t flags;
|
||||
uint32_t prio;
|
||||
};
|
||||
@@ -103,14 +96,6 @@ struct arg_value_group_list {
|
||||
uint32_t prio;
|
||||
};
|
||||
|
||||
/* a global table of possible --option values */
|
||||
struct val_props {
|
||||
int val_enum; /* foo_VAL from vals.h */
|
||||
int (*fn) (struct cmd_context *cmd, struct arg_values *av);
|
||||
const char *name;
|
||||
const char *usage;
|
||||
};
|
||||
|
||||
#define CACHE_VGMETADATA 0x00000001
|
||||
#define PERMITTED_READ_ONLY 0x00000002
|
||||
/* Process all VGs if none specified on the command line. */
|
||||
@@ -133,6 +118,19 @@ struct val_props {
|
||||
#define ENABLE_DUPLICATE_DEVS 0x00000400
|
||||
/* Command does not accept tags as args. */
|
||||
#define DISALLOW_TAG_ARGS 0x00000800
|
||||
|
||||
/* a register of the lvm commands */
|
||||
struct command {
|
||||
const char *name;
|
||||
const char *desc;
|
||||
const char *usage;
|
||||
command_fn fn;
|
||||
|
||||
unsigned flags;
|
||||
|
||||
int num_args;
|
||||
int *valid_args;
|
||||
};
|
||||
|
||||
void usage(const char *name);
|
||||
|
||||
@@ -159,8 +157,6 @@ int segtype_arg(struct cmd_context *cmd, struct arg_values *av);
|
||||
int alloc_arg(struct cmd_context *cmd, struct arg_values *av);
|
||||
int locktype_arg(struct cmd_context *cmd, struct arg_values *av);
|
||||
int readahead_arg(struct cmd_context *cmd, struct arg_values *av);
|
||||
int vgmetadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
|
||||
int pvmetadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
|
||||
int metadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
|
||||
|
||||
/* we use the enums to access the switches */
|
||||
|
137
tools/vals.h
137
tools/vals.h
@@ -1,137 +0,0 @@
|
||||
|
||||
/*
|
||||
* Define value types which describe values accepted
|
||||
* by the --option's in args.h, and can also describe
|
||||
* the values accepted as positional args.
|
||||
*
|
||||
* Previously, accepted values were only "described"
|
||||
* by identifying the parsing function to use.
|
||||
*
|
||||
* Some standard val types are used by many options,
|
||||
* e.g. many options (aa_ARG, bb_ARG, cc_ARG) all
|
||||
* accept a number_VAL.
|
||||
*
|
||||
* Other special val types are used by only one option,
|
||||
* e.g. only mirrorlog_ARG accepts a mirrorlog_VAL.
|
||||
* This typically means that there are some specific
|
||||
* words that are recognized after the option.
|
||||
*
|
||||
* Some options currently take a standard val type,
|
||||
* (esp string_VAL), but they could be given their
|
||||
* own custom val type. The advantage of using a
|
||||
* custom val type is the possibility of validating
|
||||
* the value when parsing it with a custom parsing
|
||||
* function, and the possibility of displaying the
|
||||
* actual accepted values in the command usage.
|
||||
* Without a custom val type, the code must do ad hoc
|
||||
* validation of the string values, and the usage
|
||||
* output for the option will only say "String"
|
||||
* rather than giving the accepted string values.
|
||||
* Even without a custom parsing function, there is
|
||||
* reason to define a custom x_VAL enum so that a
|
||||
* more descriptive usage string can be specified
|
||||
* as opposed to just "String".
|
||||
*
|
||||
* Most of the val types defined here are used after
|
||||
* --option's, and are referenced in foo_ARG entries
|
||||
* in args.h. But, some val types are only used to
|
||||
* represent positional values in command definitions,
|
||||
* e.g. vg_VAL.
|
||||
*
|
||||
* val(a, b, c, d)
|
||||
*
|
||||
* a: foo_VAL enums
|
||||
* b: the function to parse and set the value
|
||||
* c: the name used to reference this value in command defs
|
||||
* d: what to display in usage output for this value
|
||||
*
|
||||
* command defintions will use --option NAME, where NAME
|
||||
* is shown in val() field c. NAME will be translated to
|
||||
* foo_VAL enum in field a, which is used in commands[]
|
||||
* structs.
|
||||
*
|
||||
* option definitions (arg.h) will reference foo_VAL enum
|
||||
* in field a.
|
||||
*
|
||||
* FIXME: for specialized val types, the set of recognized
|
||||
* words is not defined or stored in a consistent way,
|
||||
* but is just whatever the parsing function happens to look
|
||||
* for, so adding a new accepted value for the val type is
|
||||
* often just making the parsing function recognize a new
|
||||
* word. This new word should then also be added to the
|
||||
* usage string for the val type here. It would be nice
|
||||
* if the accepted values could be defined in a more
|
||||
* consistent way, perhaps in struct val_props.
|
||||
*
|
||||
* The usage text for an option is not always the full
|
||||
* set of words accepted for an option, but may be a
|
||||
* subset. i.e. an outdated word that no longer does
|
||||
* anything may not be shown, but may still be recognized
|
||||
* and ignored, or an option that shouldn't be used in
|
||||
* general isn't shown to avoid suggesting it.
|
||||
* e.g. for --activate we show the most common "y|n|ay"
|
||||
* without showing the lvmlockd variations "ey|sy" which
|
||||
* are not applicable in general.
|
||||
*
|
||||
* FIXME: are there some specialized or irrelevant
|
||||
* options included in the usage text below that should
|
||||
* be removed? Should "lvm1" be removed?
|
||||
*
|
||||
* For Number args that take optional units, a full usage
|
||||
* could be "Number[bBsSkKmMgGtTpPeE]" (with implied |),
|
||||
* but repeating this full specification produces cluttered
|
||||
* output, and doesn't indicate which unit is the default.
|
||||
* "Number[units]" would be cleaner, as would a subset of
|
||||
* common units, e.g. "Number[kmg...]", but neither helps
|
||||
* with default. "Number[k|unit]" and "Number[m|unit]" show
|
||||
* the default, and "unit" indicates that other units
|
||||
* are possible without listing them all. This also
|
||||
* suggests using the preferred lower case letters, because
|
||||
* --size and other option args treat upper/lower letters
|
||||
* the same, all as 1024 SI base. For this reason, we
|
||||
* should avoid suggesting the upper case letters.
|
||||
*/
|
||||
|
||||
val(none_VAL, NULL, "None", "") /* unused, for enum value 0 */
|
||||
val(conststr_VAL, NULL, "ConstString", "") /* used only for command defs */
|
||||
val(constnum_VAL, NULL, "ConstNumber", "") /* used only for command defs */
|
||||
val(bool_VAL, yes_no_arg, "Bool", "y|n")
|
||||
val(number_VAL, int_arg, "Number", NULL)
|
||||
val(string_VAL, string_arg, "String", NULL)
|
||||
val(vg_VAL, string_arg, "VG", NULL)
|
||||
val(lv_VAL, string_arg, "LV", NULL)
|
||||
val(pv_VAL, string_arg, "PV", NULL)
|
||||
val(tag_VAL, tag_arg, "Tag", NULL)
|
||||
val(select_VAL, NULL, "Select", NULL) /* used only for command defs */
|
||||
val(activationmode_VAL, string_arg, "ActivationMode", "partial|degraded|complete")
|
||||
val(activation_VAL, activation_arg, "Active", "y|n|ay")
|
||||
val(cachemode_VAL, cachemode_arg, "CacheMode", "writethrough|writeback")
|
||||
val(discards_VAL, discards_arg, "Discards", "passdown|nopassdown|ignore")
|
||||
val(mirrorlog_VAL, mirrorlog_arg, "MirrorLog", "core|disk")
|
||||
val(sizekb_VAL, size_kb_arg, "SizeKB", "Number[k|unit]")
|
||||
val(sizemb_VAL, size_mb_arg, "SizeMB", "Number[m|unit]")
|
||||
val(numsigned_VAL, int_arg_with_sign, "SNumber", "[+|-]Number")
|
||||
val(numsignedper_VAL, int_arg_with_sign_and_percent, "SNumberP", "[+|-]Number[%{VG|PVS|FREE}]")
|
||||
val(permission_VAL, permission_arg, "Permission", "rw|r")
|
||||
val(metadatatype_VAL, metadatatype_arg, "MetadataType", "lvm2|lvm1")
|
||||
val(units_VAL, string_arg, "Units", "hHbBsSkKmMgGtTpPeE")
|
||||
val(segtype_VAL, segtype_arg, "SegType", "linear|striped|snapshot|mirror|raid*|thin|cache|thin-pool|cache-pool")
|
||||
val(alloc_VAL, alloc_arg, "Alloc", "contiguous|cling|cling_by_tags|normal|anywhere|inherit")
|
||||
val(locktype_VAL, locktype_arg, "LockType", "sanlock|dlm|none")
|
||||
val(readahead_VAL, readahead_arg, "Readahead", "auto|none|NumberSectors")
|
||||
val(vgmetadatacopies_VAL, vgmetadatacopies_arg, "MetadataCopiesVG", "all|unmanaged|Number")
|
||||
val(pvmetadatacopies_VAL, pvmetadatacopies_arg, "MetadataCopiesPV", "0|1|2")
|
||||
val(metadatacopies_VAL, metadatacopies_arg, "unused", "unused")
|
||||
|
||||
/* this should always be last */
|
||||
val(VAL_COUNT, NULL, NULL, NULL)
|
||||
|
||||
/*
|
||||
* FIXME: I suspect many of the following are good candidates for a custom VAL
|
||||
* enum for the benefit of custom parsing, or custom usage, or both:
|
||||
*
|
||||
* configreport_ARG, configtype_ARG, polloperation_ARG, raidrebuild_ARG,
|
||||
* raidsyncaction_ARG, raidwritemostly_ARG, reportformat_ARG, syncaction_ARG,
|
||||
* cachepolicy_ARG, cachesettings_ARG, writemostly_ARG
|
||||
*/
|
||||
|
@@ -482,9 +482,6 @@ static int _vgchange_metadata_copies(struct cmd_context *cmd,
|
||||
{
|
||||
uint32_t mda_copies = arg_uint_value(cmd, vgmetadatacopies_ARG, DEFAULT_VGMETADATACOPIES);
|
||||
|
||||
log_warn("vgchange_metadata_copies new %u vg_mda_copies %u D %u",
|
||||
mda_copies, vg_mda_copies(vg), DEFAULT_VGMETADATACOPIES);
|
||||
|
||||
if (mda_copies == vg_mda_copies(vg)) {
|
||||
if (vg_mda_copies(vg) == VGMETADATACOPIES_UNMANAGED)
|
||||
log_warn("Number of metadata copies for VG %s is already unmanaged.",
|
||||
|
@@ -157,12 +157,24 @@ int vgconvert(struct cmd_context *cmd, int argc, char **argv)
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_is_set(cmd, metadatacopies_ARG)) {
|
||||
log_error("Invalid option --metadatacopies, "
|
||||
"use --pvmetadatacopies instead.");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
if (!(cmd->fmt->features & FMT_MDAS) &&
|
||||
arg_is_set(cmd, pvmetadatacopies_ARG)) {
|
||||
(arg_is_set(cmd, pvmetadatacopies_ARG) ||
|
||||
arg_is_set(cmd, metadatasize_ARG))) {
|
||||
log_error("Metadata parameters only apply to text format");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_is_set(cmd, pvmetadatacopies_ARG) &&
|
||||
arg_int_value(cmd, pvmetadatacopies_ARG, -1) > 2) {
|
||||
log_error("Metadatacopies may only be 0, 1 or 2");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (!(cmd->fmt->features & FMT_BAS) &&
|
||||
arg_is_set(cmd, bootloaderareasize_ARG)) {
|
||||
log_error("Bootloader area parameters only apply to text format");
|
||||
|
@@ -136,6 +136,12 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv)
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_is_set(cmd, metadatacopies_ARG)) {
|
||||
log_error("Invalid option --metadatacopies, "
|
||||
"use --pvmetadatacopies instead.");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
vg_name = skip_dev_dir(cmd, argv[0], NULL);
|
||||
argc--;
|
||||
argv++;
|
||||
|
Reference in New Issue
Block a user