mirror of
git://sourceware.org/git/lvm2.git
synced 2025-10-08 19:33:19 +03:00
Compare commits
64 Commits
dev-dct-cm
...
dev-dct-cm
Author | SHA1 | Date | |
---|---|---|---|
|
7a79dc8a63 | ||
|
d7e9a10fb4 | ||
|
10521c0e64 | ||
|
ad21ae9cfc | ||
|
b01d88626d | ||
|
6de05cf5f5 | ||
|
cd0736a945 | ||
|
68d6d342f8 | ||
|
e7da8e7e1f | ||
|
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)
|
||||||
|
17
WHATS_NEW
17
WHATS_NEW
@@ -1,5 +1,18 @@
|
|||||||
Version 2.02.167 -
|
Version 2.02.168 -
|
||||||
======================================
|
====================================
|
||||||
|
Only log msg as debug if lvm2-lvmdbusd unit missing for D-Bus notification.
|
||||||
|
Missing stripe filler now could be also 'zero'.
|
||||||
|
lvconvert --repair accepts --interval and --background option.
|
||||||
|
More efficiently prepare _rmeta devices when creating a new raid LV.
|
||||||
|
|
||||||
|
Version 2.02.167 - 5th November 2016
|
||||||
|
====================================
|
||||||
|
Use log_error in regex and sysfs filter to describe reason of failure.
|
||||||
|
Fix blkdeactivate to deactivate dev stack if dev on top already unmounted.
|
||||||
|
Prevent non-synced raid1 repair unless --force
|
||||||
|
Prevent raid4 creation/conversion on non-supporting kernels
|
||||||
|
Add direct striped -> raid4 conversion
|
||||||
|
Fix raid4 parity image pair position on conversions from striped/raid0*
|
||||||
Fix a few unconverted return code values for some lvconvert error path.
|
Fix a few unconverted return code values for some lvconvert error path.
|
||||||
Disable lvconvert of thin pool to raid while active.
|
Disable lvconvert of thin pool to raid while active.
|
||||||
Disable systemd service start rate limiting for lvm2-pvscan@.service.
|
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 and report pthread_sigmask() failure in dmeventd.
|
||||||
Check mem alloc fail in _canonicalize_field_ids().
|
Check mem alloc fail in _canonicalize_field_ids().
|
||||||
Use unsigned math when checking more then 31 legs of raid.
|
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;
|
static char **_initial_registrations = 0;
|
||||||
|
|
||||||
/* FIXME Make configurable at runtime */
|
/* FIXME Make configurable at runtime */
|
||||||
__attribute__((format(printf, 4, 5)))
|
|
||||||
static void _dmeventd_log(int level, const char *file, int line,
|
/* All libdm messages */
|
||||||
const char *format, ...)
|
__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_list ap;
|
||||||
va_start(ap, format);
|
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);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2191,7 +2206,7 @@ int main(int argc, char *argv[])
|
|||||||
openlog("dmeventd", LOG_PID, LOG_DAEMON);
|
openlog("dmeventd", LOG_PID, LOG_DAEMON);
|
||||||
|
|
||||||
dm_event_log_set(_debug_level, _use_syslog);
|
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);
|
(void) dm_prepare_selinux_context(DMEVENTD_PIDFILE, S_IFREG);
|
||||||
if (dm_create_lockfile(DMEVENTD_PIDFILE) == 0)
|
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,
|
int line, int dm_errno_or_class,
|
||||||
const char *format, va_list ap)
|
const char *format, va_list ap)
|
||||||
{
|
{
|
||||||
|
static int _abort_on_internal_errors = -1;
|
||||||
static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
static time_t start = 0;
|
static time_t start = 0;
|
||||||
const char *indent = "";
|
const char *indent = "";
|
||||||
FILE *stream = stdout;
|
FILE *stream = log_stderr(level) ? stderr : stdout;
|
||||||
int prio;
|
int prio;
|
||||||
time_t now;
|
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:
|
case _LOG_DEBUG:
|
||||||
|
/* Never shown without -ddd */
|
||||||
if (_debug_level < 3)
|
if (_debug_level < 3)
|
||||||
return;
|
return;
|
||||||
prio = LOG_DEBUG;
|
prio = LOG_DEBUG;
|
||||||
indent = " ";
|
indent = " ";
|
||||||
break;
|
break;
|
||||||
case _LOG_INFO:
|
case _LOG_INFO:
|
||||||
if (_debug_level < 2)
|
if (log_with_debug && _debug_level < 2)
|
||||||
return;
|
return;
|
||||||
prio = LOG_INFO;
|
prio = LOG_INFO;
|
||||||
indent = " ";
|
indent = " ";
|
||||||
break;
|
break;
|
||||||
case _LOG_NOTICE:
|
case _LOG_NOTICE:
|
||||||
if (_debug_level < 1)
|
if (log_with_debug && _debug_level < 1)
|
||||||
return;
|
return;
|
||||||
prio = LOG_NOTICE;
|
prio = LOG_NOTICE;
|
||||||
indent = " ";
|
indent = " ";
|
||||||
@@ -912,12 +922,13 @@ void dm_event_log(const char *subsys, int level, const char *file,
|
|||||||
if (!start)
|
if (!start)
|
||||||
start = now;
|
start = now;
|
||||||
now -= start;
|
now -= start;
|
||||||
fprintf(stream, "[%2d:%02d] %8x:%-6s%s",
|
if (_debug_level)
|
||||||
(int)now / 60, (int)now % 60,
|
fprintf(stream, "[%2d:%02d] %8x:%-6s%s",
|
||||||
// TODO: Maybe use shorter ID
|
(int)now / 60, (int)now % 60,
|
||||||
// ((int)(pthread_self()) >> 6) & 0xffff,
|
// TODO: Maybe use shorter ID
|
||||||
(int)pthread_self(), subsys,
|
// ((int)(pthread_self()) >> 6) & 0xffff,
|
||||||
(_debug_level > 3) ? "" : indent);
|
(int)pthread_self(), subsys,
|
||||||
|
(_debug_level > 3) ? "" : indent);
|
||||||
if (_debug_level > 3)
|
if (_debug_level > 3)
|
||||||
fprintf(stream, "%28s:%4d %s", file, line, indent);
|
fprintf(stream, "%28s:%4d %s", file, line, indent);
|
||||||
vfprintf(stream, _(format), ap);
|
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);
|
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 */
|
#if 0 /* left out for now */
|
||||||
|
@@ -32,7 +32,7 @@ static int _register_count = 0;
|
|||||||
static struct dm_pool *_mem_pool = NULL;
|
static struct dm_pool *_mem_pool = NULL;
|
||||||
static void *_lvm_handle = 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,
|
static void _lvm2_print_log(int level, const char *file, int line,
|
||||||
int dm_errno_or_class, const char *msg)
|
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;
|
unsigned i;
|
||||||
struct dm_status_mirror *ms;
|
struct dm_status_mirror *ms;
|
||||||
|
|
||||||
if (!dm_get_status_mirror(state->mem, params, &ms))
|
if (!dm_get_status_mirror(state->mem, params, &ms)) {
|
||||||
goto_out;
|
log_error("Unable to parse mirror status string.");
|
||||||
|
return ME_IGNORE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check for bad mirror devices */
|
/* Check for bad mirror devices */
|
||||||
for (i = 0; i < ms->dev_count; ++i)
|
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);
|
dm_pool_free(state->mem, ms);
|
||||||
|
|
||||||
return r;
|
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))
|
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 */
|
/* 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.",
|
log_info("Repair of mirrored device %s finished successfully.", device);
|
||||||
(r) ? "finished successfully" : "failed");
|
|
||||||
|
|
||||||
return r;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_event(struct dm_task *dmt,
|
void process_event(struct dm_task *dmt,
|
||||||
@@ -154,7 +152,8 @@ void process_event(struct dm_task *dmt,
|
|||||||
case ME_FAILURE:
|
case ME_FAILURE:
|
||||||
log_error("Device failure in %s.", device);
|
log_error("Device failure in %s.", device);
|
||||||
if (!_remove_failed_devices(state->cmd_lvscan,
|
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? */
|
/* FIXME Why are all the error return codes unused? Get rid of them? */
|
||||||
log_error("Failed to remove faulty devices in %s.",
|
log_error("Failed to remove faulty devices in %s.",
|
||||||
device);
|
device);
|
||||||
@@ -168,7 +167,7 @@ void process_event(struct dm_task *dmt,
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* FIXME Provide value then! */
|
/* FIXME Provide value then! */
|
||||||
log_info("Unknown event received.");
|
log_warn("WARNING: %s received unknown event.", device);
|
||||||
}
|
}
|
||||||
} while (next);
|
} 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 repair goes OK, report success even if lvscan has failed */
|
||||||
if (!dmeventd_lvm2_run_with_lock(state->cmd_lvconvert)) {
|
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;
|
r = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@@ -301,7 +301,7 @@ out:
|
|||||||
static int _use_policy(struct dm_task *dmt, struct dso_state *state)
|
static int _use_policy(struct dm_task *dmt, struct dso_state *state)
|
||||||
{
|
{
|
||||||
#if THIN_DEBUG
|
#if THIN_DEBUG
|
||||||
log_info("dmeventd executes: %s.", state->cmd_str);
|
log_debug("dmeventd executes: %s.", state->cmd_str);
|
||||||
#endif
|
#endif
|
||||||
if (!dmeventd_lvm2_run_with_lock(state->cmd_str)) {
|
if (!dmeventd_lvm2_run_with_lock(state->cmd_str)) {
|
||||||
log_error("Failed to extend thin pool %s.",
|
log_error("Failed to extend thin pool %s.",
|
||||||
|
@@ -7,19 +7,13 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import threading
|
|
||||||
import subprocess
|
import subprocess
|
||||||
from . import cfg
|
from . import cfg
|
||||||
import time
|
|
||||||
from .cmdhandler import options_to_cli_args
|
from .cmdhandler import options_to_cli_args
|
||||||
import dbus
|
import dbus
|
||||||
from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug
|
from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug
|
||||||
import traceback
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
_rlock = threading.RLock()
|
|
||||||
_thread_list = list()
|
|
||||||
|
|
||||||
|
|
||||||
def pv_move_lv_cmd(move_options, lv_full_name,
|
def pv_move_lv_cmd(move_options, lv_full_name,
|
||||||
pv_source, pv_source_range, pv_dest_range_list):
|
pv_source, pv_source_range, pv_dest_range_list):
|
||||||
@@ -42,15 +36,40 @@ def lv_merge_cmd(merge_options, lv_full_name):
|
|||||||
return cmd
|
return cmd
|
||||||
|
|
||||||
|
|
||||||
def _move_merge(interface_name, cmd, job_state):
|
def _move_merge(interface_name, command, job_state):
|
||||||
add(cmd, 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)
|
log_debug("Background process for %s is %d" %
|
||||||
if not done:
|
(str(command), process.pid))
|
||||||
ec, err_msg = job_state.GetError
|
|
||||||
|
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(
|
raise dbus.exceptions.DBusException(
|
||||||
interface_name,
|
interface_name,
|
||||||
'Exit code %s, stderr = %s' % (str(ec), err_msg))
|
'Exit code %s, stderr = %s' % (str(process.returncode), out[1]))
|
||||||
|
|
||||||
cfg.load()
|
cfg.load()
|
||||||
return '/'
|
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]))
|
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,
|
cmd = pv_move_lv_cmd(move_options,
|
||||||
lv_name,
|
lv_name,
|
||||||
pv_src.lvm_id,
|
pv_src.lvm_id,
|
||||||
@@ -109,106 +126,3 @@ def merge(interface_name, lv_uuid, lv_name, merge_options, job_state):
|
|||||||
raise dbus.exceptions.DBusException(
|
raise dbus.exceptions.DBusException(
|
||||||
interface_name,
|
interface_name,
|
||||||
'LV with uuid %s and name %s not present!' % (lv_uuid, lv_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 .vg import load_vgs
|
||||||
from .lv import load_lvs
|
from .lv import load_lvs
|
||||||
from . import cfg
|
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 = 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
|
# Go through and load all the PVs, VGs and LVs
|
||||||
if cache_refresh:
|
if cache_refresh:
|
||||||
cfg.db.refresh(log)
|
cfg.db.refresh(log)
|
||||||
|
|
||||||
num_total_changes += load_pvs(refresh=refresh, emit_signal=emit_signal,
|
if need_main_thread:
|
||||||
cache_refresh=False)[1]
|
rc = MThreadRunner(_main_thread_load, refresh, emit_signal).done()
|
||||||
num_total_changes += load_vgs(refresh=refresh, emit_signal=emit_signal,
|
else:
|
||||||
cache_refresh=False)[1]
|
rc = _main_thread_load(refresh, emit_signal)
|
||||||
num_total_changes += load_lvs(refresh=refresh, emit_signal=emit_signal,
|
|
||||||
cache_refresh=False)[1]
|
|
||||||
|
|
||||||
return num_total_changes
|
return rc
|
||||||
|
@@ -8,12 +8,54 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from .automatedproperties import AutomatedProperties
|
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 . import cfg
|
||||||
from .cfg import JOB_INTERFACE
|
from .cfg import JOB_INTERFACE
|
||||||
import dbus
|
import dbus
|
||||||
import threading
|
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
|
# noinspection PyPep8Naming
|
||||||
@@ -24,9 +66,9 @@ class JobState(object):
|
|||||||
self._percent = 0
|
self._percent = 0
|
||||||
self._complete = False
|
self._complete = False
|
||||||
self._request = request
|
self._request = request
|
||||||
self._cond = threading.Condition(self.rlock)
|
|
||||||
self._ec = 0
|
self._ec = 0
|
||||||
self._stderr = ''
|
self._stderr = ''
|
||||||
|
self._waiting_clients = []
|
||||||
|
|
||||||
# This is an lvm command that is just taking too long and doesn't
|
# This is an lvm command that is just taking too long and doesn't
|
||||||
# support background operation
|
# support background operation
|
||||||
@@ -57,7 +99,7 @@ class JobState(object):
|
|||||||
with self.rlock:
|
with self.rlock:
|
||||||
self._complete = value
|
self._complete = value
|
||||||
self._percent = 100
|
self._percent = 100
|
||||||
self._cond.notify_all()
|
self.notify_waiting_clients()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def GetError(self):
|
def GetError(self):
|
||||||
@@ -71,29 +113,10 @@ class JobState(object):
|
|||||||
else:
|
else:
|
||||||
return (-1, 'Job is not complete!')
|
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):
|
def dtor(self):
|
||||||
with self.rlock:
|
with self.rlock:
|
||||||
self._request = None
|
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
|
@property
|
||||||
def Result(self):
|
def Result(self):
|
||||||
with self.rlock:
|
with self.rlock:
|
||||||
@@ -101,6 +124,36 @@ class JobState(object):
|
|||||||
return self._request.result()
|
return self._request.result()
|
||||||
return '/'
|
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
|
# noinspection PyPep8Naming
|
||||||
class Job(AutomatedProperties):
|
class Job(AutomatedProperties):
|
||||||
@@ -122,10 +175,6 @@ class Job(AutomatedProperties):
|
|||||||
def Percent(self):
|
def Percent(self):
|
||||||
return dbus.Double(float(self.state.Percent))
|
return dbus.Double(float(self.state.Percent))
|
||||||
|
|
||||||
@Percent.setter
|
|
||||||
def Percent(self, value):
|
|
||||||
self.state.Percent = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def Complete(self):
|
def Complete(self):
|
||||||
return dbus.Boolean(self.state.Complete)
|
return dbus.Boolean(self.state.Complete)
|
||||||
@@ -138,9 +187,6 @@ class Job(AutomatedProperties):
|
|||||||
def GetError(self):
|
def GetError(self):
|
||||||
return dbus.Struct(self.state.GetError, signature="(is)")
|
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)
|
@dbus.service.method(dbus_interface=JOB_INTERFACE)
|
||||||
def Remove(self):
|
def Remove(self):
|
||||||
if self.state.Complete:
|
if self.state.Complete:
|
||||||
@@ -155,7 +201,11 @@ class Job(AutomatedProperties):
|
|||||||
out_signature='b',
|
out_signature='b',
|
||||||
async_callbacks=('cb', 'cbe'))
|
async_callbacks=('cb', 'cbe'))
|
||||||
def Wait(self, timeout, 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
|
@property
|
||||||
def Result(self):
|
def Result(self):
|
||||||
|
@@ -21,7 +21,7 @@ from .utils import n, n32
|
|||||||
from .loader import common
|
from .loader import common
|
||||||
from .state import State
|
from .state import State
|
||||||
from . import background
|
from . import background
|
||||||
from .utils import round_size
|
from .utils import round_size, mt_remove_dbus_objects
|
||||||
from .job import JobState
|
from .job import JobState
|
||||||
|
|
||||||
|
|
||||||
@@ -415,7 +415,6 @@ class Lv(LvCommon):
|
|||||||
rc, out, err = cmdhandler.lv_remove(lv_name, remove_options)
|
rc, out, err = cmdhandler.lv_remove(lv_name, remove_options)
|
||||||
|
|
||||||
if rc == 0:
|
if rc == 0:
|
||||||
cfg.om.remove_object(dbo, True)
|
|
||||||
cfg.load()
|
cfg.load()
|
||||||
else:
|
else:
|
||||||
# Need to work on error handling, need consistent
|
# Need to work on error handling, need consistent
|
||||||
@@ -515,15 +514,9 @@ class Lv(LvCommon):
|
|||||||
rc, out, err = cmdhandler.vg_lv_snapshot(
|
rc, out, err = cmdhandler.vg_lv_snapshot(
|
||||||
lv_name, snapshot_options, name, optional_size)
|
lv_name, snapshot_options, name, optional_size)
|
||||||
if rc == 0:
|
if rc == 0:
|
||||||
return_path = '/'
|
cfg.load()
|
||||||
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
|
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
|
||||||
lvs = load_lvs([full_name], emit_signal=True)[0]
|
return cfg.om.get_object_path_by_lvm_id(full_name)
|
||||||
for l in lvs:
|
|
||||||
return_path = l.dbus_object_path()
|
|
||||||
|
|
||||||
# Refresh self and all included PVs
|
|
||||||
cfg.load(cache_refresh=False)
|
|
||||||
return return_path
|
|
||||||
else:
|
else:
|
||||||
raise dbus.exceptions.DBusException(
|
raise dbus.exceptions.DBusException(
|
||||||
LV_INTERFACE,
|
LV_INTERFACE,
|
||||||
@@ -752,9 +745,8 @@ class LvThinPool(Lv):
|
|||||||
lv_name, create_options, name, size_bytes)
|
lv_name, create_options, name, size_bytes)
|
||||||
if rc == 0:
|
if rc == 0:
|
||||||
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
|
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
|
||||||
lvs = load_lvs([full_name], emit_signal=True)[0]
|
cfg.load()
|
||||||
for l in lvs:
|
lv_created = cfg.om.get_object_path_by_lvm_id(full_name)
|
||||||
lv_created = l.dbus_object_path()
|
|
||||||
else:
|
else:
|
||||||
raise dbus.exceptions.DBusException(
|
raise dbus.exceptions.DBusException(
|
||||||
LV_INTERFACE,
|
LV_INTERFACE,
|
||||||
@@ -816,8 +808,7 @@ class LvCachePool(Lv):
|
|||||||
# When we cache an LV, the cache pool and the lv that is getting
|
# When we cache an LV, the cache pool and the lv that is getting
|
||||||
# cached need to be removed from the object manager and
|
# cached need to be removed from the object manager and
|
||||||
# re-created as their interfaces have changed!
|
# re-created as their interfaces have changed!
|
||||||
cfg.om.remove_object(dbo, emit_signal=True)
|
mt_remove_dbus_objects((dbo, lv_to_cache))
|
||||||
cfg.om.remove_object(lv_to_cache, emit_signal=True)
|
|
||||||
cfg.load()
|
cfg.load()
|
||||||
|
|
||||||
lv_converted = cfg.om.get_object_path_by_lvm_id(fcn)
|
lv_converted = cfg.om.get_object_path_by_lvm_id(fcn)
|
||||||
@@ -879,8 +870,7 @@ class LvCacheLv(Lv):
|
|||||||
if rc == 0:
|
if rc == 0:
|
||||||
# The cache pool gets removed as hidden and put back to
|
# The cache pool gets removed as hidden and put back to
|
||||||
# visible, so lets delete
|
# visible, so lets delete
|
||||||
cfg.om.remove_object(cache_pool, emit_signal=True)
|
mt_remove_dbus_objects((cache_pool, dbo))
|
||||||
cfg.om.remove_object(dbo, emit_signal=True)
|
|
||||||
cfg.load()
|
cfg.load()
|
||||||
|
|
||||||
uncached_lv_path = cfg.om.get_object_path_by_lvm_id(lv_name)
|
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 gi.repository import GLib
|
||||||
from .fetch import load
|
from .fetch import load
|
||||||
from .manager import Manager
|
from .manager import Manager
|
||||||
from .background import background_reaper
|
|
||||||
import traceback
|
import traceback
|
||||||
import queue
|
import queue
|
||||||
from . import udevwatch
|
from . import udevwatch
|
||||||
@@ -64,6 +63,7 @@ def _discard_pending_refreshes():
|
|||||||
|
|
||||||
def process_request():
|
def process_request():
|
||||||
while cfg.run.value != 0:
|
while cfg.run.value != 0:
|
||||||
|
# noinspection PyBroadException
|
||||||
try:
|
try:
|
||||||
req = cfg.worker_q.get(True, 5)
|
req = cfg.worker_q.get(True, 5)
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ def process_request():
|
|||||||
log_debug(
|
log_debug(
|
||||||
"Inspect method %s for too many refreshes" %
|
"Inspect method %s for too many refreshes" %
|
||||||
(str(req.method)))
|
(str(req.method)))
|
||||||
log_debug("Complete ")
|
log_debug("Method complete ")
|
||||||
except queue.Empty:
|
except queue.Empty:
|
||||||
pass
|
pass
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -156,14 +156,11 @@ def main():
|
|||||||
|
|
||||||
cfg.db = lvmdb.DataStore(cfg.args.use_json)
|
cfg.db = lvmdb.DataStore(cfg.args.use_json)
|
||||||
|
|
||||||
# Start up thread to monitor pv moves
|
# Using a thread to process requests, we cannot hang the dbus library
|
||||||
thread_list.append(
|
# thread that is handling the dbus interface
|
||||||
threading.Thread(target=background_reaper, name="pv_move_reaper"))
|
|
||||||
|
|
||||||
# Using a thread to process requests.
|
|
||||||
thread_list.append(threading.Thread(target=process_request))
|
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()
|
cfg.loop = GLib.MainLoop()
|
||||||
|
|
||||||
for process in thread_list:
|
for process in thread_list:
|
||||||
|
@@ -42,12 +42,10 @@ class Manager(AutomatedProperties):
|
|||||||
raise dbus.exceptions.DBusException(
|
raise dbus.exceptions.DBusException(
|
||||||
MANAGER_INTERFACE, "PV Already exists!")
|
MANAGER_INTERFACE, "PV Already exists!")
|
||||||
|
|
||||||
created_pv = []
|
|
||||||
rc, out, err = cmdhandler.pv_create(create_options, [device])
|
rc, out, err = cmdhandler.pv_create(create_options, [device])
|
||||||
if rc == 0:
|
if rc == 0:
|
||||||
pvs = load_pvs([device], emit_signal=True)[0]
|
cfg.load()
|
||||||
for p in pvs:
|
created_pv = cfg.om.get_object_path_by_lvm_id(device)
|
||||||
created_pv = p.dbus_object_path()
|
|
||||||
else:
|
else:
|
||||||
raise dbus.exceptions.DBusException(
|
raise dbus.exceptions.DBusException(
|
||||||
MANAGER_INTERFACE,
|
MANAGER_INTERFACE,
|
||||||
@@ -80,20 +78,14 @@ class Manager(AutomatedProperties):
|
|||||||
MANAGER_INTERFACE, 'object path = %s not found' % p)
|
MANAGER_INTERFACE, 'object path = %s not found' % p)
|
||||||
|
|
||||||
rc, out, err = cmdhandler.vg_create(create_options, pv_devices, name)
|
rc, out, err = cmdhandler.vg_create(create_options, pv_devices, name)
|
||||||
created_vg = "/"
|
|
||||||
|
|
||||||
if rc == 0:
|
if rc == 0:
|
||||||
vgs = load_vgs([name], emit_signal=True)[0]
|
cfg.load()
|
||||||
for v in vgs:
|
return cfg.om.get_object_path_by_lvm_id(name)
|
||||||
created_vg = v.dbus_object_path()
|
|
||||||
|
|
||||||
# Update the PVS
|
|
||||||
load_pvs(refresh=True, emit_signal=True, cache_refresh=False)
|
|
||||||
else:
|
else:
|
||||||
raise dbus.exceptions.DBusException(
|
raise dbus.exceptions.DBusException(
|
||||||
MANAGER_INTERFACE,
|
MANAGER_INTERFACE,
|
||||||
'Exit code %s, stderr = %s' % (str(rc), err))
|
'Exit code %s, stderr = %s' % (str(rc), err))
|
||||||
return created_vg
|
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
dbus_interface=MANAGER_INTERFACE,
|
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 .loader import common
|
||||||
from .request import RequestEntry
|
from .request import RequestEntry
|
||||||
from .state import State
|
from .state import State
|
||||||
from .utils import round_size
|
from .utils import round_size, mt_remove_dbus_objects
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyUnusedLocal
|
# noinspection PyUnusedLocal
|
||||||
@@ -140,7 +140,7 @@ class Pv(AutomatedProperties):
|
|||||||
if dbo:
|
if dbo:
|
||||||
rc, out, err = cmdhandler.pv_remove(pv_name, remove_options)
|
rc, out, err = cmdhandler.pv_remove(pv_name, remove_options)
|
||||||
if rc == 0:
|
if rc == 0:
|
||||||
cfg.om.remove_object(dbo, True)
|
mt_remove_dbus_objects((dbo,))
|
||||||
else:
|
else:
|
||||||
# Need to work on error handling, need consistent
|
# Need to work on error handling, need consistent
|
||||||
raise dbus.exceptions.DBusException(
|
raise dbus.exceptions.DBusException(
|
||||||
@@ -174,7 +174,7 @@ class Pv(AutomatedProperties):
|
|||||||
rc, out, err = cmdhandler.pv_resize(pv_name, new_size_bytes,
|
rc, out, err = cmdhandler.pv_resize(pv_name, new_size_bytes,
|
||||||
resize_options)
|
resize_options)
|
||||||
if rc == 0:
|
if rc == 0:
|
||||||
dbo.refresh()
|
cfg.load()
|
||||||
else:
|
else:
|
||||||
raise dbus.exceptions.DBusException(
|
raise dbus.exceptions.DBusException(
|
||||||
PV_INTERFACE,
|
PV_INTERFACE,
|
||||||
|
@@ -13,7 +13,7 @@ from gi.repository import GLib
|
|||||||
from .job import Job
|
from .job import Job
|
||||||
from . import cfg
|
from . import cfg
|
||||||
import traceback
|
import traceback
|
||||||
from .utils import log_error
|
from .utils import log_error, mt_async_result
|
||||||
|
|
||||||
|
|
||||||
class RequestEntry(object):
|
class RequestEntry(object):
|
||||||
@@ -57,9 +57,9 @@ class RequestEntry(object):
|
|||||||
self._job = Job(self, self._job_state)
|
self._job = Job(self, self._job_state)
|
||||||
cfg.om.register_object(self._job, True)
|
cfg.om.register_object(self._job, True)
|
||||||
if self._return_tuple:
|
if self._return_tuple:
|
||||||
self.cb(('/', self._job.dbus_object_path()))
|
mt_async_result(self.cb, ('/', self._job.dbus_object_path()))
|
||||||
else:
|
else:
|
||||||
self.cb(self._job.dbus_object_path())
|
mt_async_result(self.cb, self._job.dbus_object_path())
|
||||||
|
|
||||||
def run_cmd(self):
|
def run_cmd(self):
|
||||||
try:
|
try:
|
||||||
@@ -110,9 +110,9 @@ class RequestEntry(object):
|
|||||||
if error_rc == 0:
|
if error_rc == 0:
|
||||||
if self.cb:
|
if self.cb:
|
||||||
if self._return_tuple:
|
if self._return_tuple:
|
||||||
self.cb((result, '/'))
|
mt_async_result(self.cb, (result, '/'))
|
||||||
else:
|
else:
|
||||||
self.cb(result)
|
mt_async_result(self.cb, result)
|
||||||
else:
|
else:
|
||||||
if self.cb_error:
|
if self.cb_error:
|
||||||
if not error_exception:
|
if not error_exception:
|
||||||
@@ -123,7 +123,7 @@ class RequestEntry(object):
|
|||||||
else:
|
else:
|
||||||
error_exception = Exception(error_msg)
|
error_exception = Exception(error_msg)
|
||||||
|
|
||||||
self.cb_error(error_exception)
|
mt_async_result(self.cb_error, error_exception)
|
||||||
else:
|
else:
|
||||||
# We have a job and it's complete, indicate that it's done.
|
# We have a job and it's complete, indicate that it's done.
|
||||||
# TODO: We need to signal the job is done too.
|
# TODO: We need to signal the job is done too.
|
||||||
|
@@ -17,6 +17,8 @@ import datetime
|
|||||||
|
|
||||||
import dbus
|
import dbus
|
||||||
from lvmdbusd import cfg
|
from lvmdbusd import cfg
|
||||||
|
from gi.repository import GLib
|
||||||
|
import threading
|
||||||
|
|
||||||
|
|
||||||
STDOUT_TTY = os.isatty(sys.stdout.fileno())
|
STDOUT_TTY = os.isatty(sys.stdout.fileno())
|
||||||
@@ -494,3 +496,64 @@ def validate_tag(interface, tag):
|
|||||||
raise dbus.exceptions.DBusException(
|
raise dbus.exceptions.DBusException(
|
||||||
interface, 'tag (%s) contains invalid character, allowable set(%s)'
|
interface, 'tag (%s) contains invalid character, allowable set(%s)'
|
||||||
% (tag, _ALLOWABLE_TAG_CH))
|
% (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 .loader import common
|
||||||
from .state import State
|
from .state import State
|
||||||
from . import background
|
from . import background
|
||||||
from .utils import round_size
|
from .utils import round_size, mt_remove_dbus_objects
|
||||||
from .job import JobState
|
from .job import JobState
|
||||||
|
|
||||||
|
|
||||||
@@ -191,14 +191,7 @@ class Vg(AutomatedProperties):
|
|||||||
rc, out, err = cmdhandler.vg_remove(vg_name, remove_options)
|
rc, out, err = cmdhandler.vg_remove(vg_name, remove_options)
|
||||||
|
|
||||||
if rc == 0:
|
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()
|
cfg.load()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Need to work on error handling, need consistent
|
# Need to work on error handling, need consistent
|
||||||
raise dbus.exceptions.DBusException(
|
raise dbus.exceptions.DBusException(
|
||||||
@@ -605,9 +598,7 @@ class Vg(AutomatedProperties):
|
|||||||
rc, out, err = create_method(
|
rc, out, err = create_method(
|
||||||
md.lv_full_name(), data.lv_full_name(), create_options)
|
md.lv_full_name(), data.lv_full_name(), create_options)
|
||||||
if rc == 0:
|
if rc == 0:
|
||||||
cfg.om.remove_object(md, emit_signal=True)
|
mt_remove_dbus_objects((md, data))
|
||||||
cfg.om.remove_object(data, emit_signal=True)
|
|
||||||
|
|
||||||
cache_pool_lv = Vg.fetch_new_lv(vg_name, new_name)
|
cache_pool_lv = Vg.fetch_new_lv(vg_name, new_name)
|
||||||
else:
|
else:
|
||||||
raise dbus.exceptions.DBusException(
|
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)
|
int lv_is_active(const struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1489,6 +1494,26 @@ out:
|
|||||||
return r || l;
|
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)
|
int lv_is_active(const struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
return _lv_is_active(lv, NULL, NULL, NULL);
|
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)
|
if (!r)
|
||||||
return_0;
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
* Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
|
* Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is part of LVM2.
|
* 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 use_modprobe);
|
||||||
int target_version(const char *target_name, uint32_t *maj,
|
int target_version(const char *target_name, uint32_t *maj,
|
||||||
uint32_t *min, uint32_t *patchlevel);
|
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 lvm_dm_prefix_check(int major, int minor, const char *prefix);
|
||||||
int list_segment_modules(struct dm_pool *mem, const struct lv_segment *seg,
|
int list_segment_modules(struct dm_pool *mem, const struct lv_segment *seg,
|
||||||
struct dm_list *modules);
|
struct dm_list *modules);
|
||||||
|
@@ -2250,8 +2250,8 @@ bad:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *_add_error_device(struct dev_manager *dm, struct dm_tree *dtree,
|
static char *_add_error_or_zero_device(struct dev_manager *dm, struct dm_tree *dtree,
|
||||||
struct lv_segment *seg, int s)
|
struct lv_segment *seg, int s, int use_zero)
|
||||||
{
|
{
|
||||||
char *dlid, *name;
|
char *dlid, *name;
|
||||||
char errid[32];
|
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;
|
uint64_t size = (uint64_t) seg->len * seg->lv->vg->extent_size;
|
||||||
|
|
||||||
dm_list_iterate_items(seg_i, &seg->lv->segments) {
|
dm_list_iterate_items(seg_i, &seg->lv->segments) {
|
||||||
if (seg == seg_i)
|
if (seg == seg_i) {
|
||||||
segno = i;
|
segno = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (segno < 0) {
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2281,7 +2283,7 @@ static char *_add_error_device(struct dev_manager *dm, struct dm_tree *dtree,
|
|||||||
seg->lv->name, errid)))
|
seg->lv->name, errid)))
|
||||||
return_NULL;
|
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)) {
|
if (!_info(dm->cmd, dlid, 1, 0, &info, NULL, NULL)) {
|
||||||
log_error("Failed to get info for %s [%s].", name, dlid);
|
log_error("Failed to get info for %s [%s].", name, dlid);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -2291,14 +2293,19 @@ static char *_add_error_device(struct dev_manager *dm, struct dm_tree *dtree,
|
|||||||
/* Create new node */
|
/* Create new node */
|
||||||
if (!(node = dm_tree_add_new_dev(dtree, name, dlid, 0, 0, 0, 0, 0)))
|
if (!(node = dm_tree_add_new_dev(dtree, name, dlid, 0, 0, 0, 0, 0)))
|
||||||
return_NULL;
|
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 {
|
} else {
|
||||||
/* Already exists */
|
/* Already exists */
|
||||||
if (!dm_tree_add_dev(dtree, info.major, info.minor)) {
|
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);
|
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;
|
char *dlid;
|
||||||
uint64_t extent_size = seg->lv->vg->extent_size;
|
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
|
* FIXME, the tree pointer is first field of dm_tree_node, but
|
||||||
* we don't have the struct definition available.
|
* we don't have the struct definition available.
|
||||||
*/
|
*/
|
||||||
struct dm_tree **tree = (struct dm_tree **) node;
|
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;
|
return_0;
|
||||||
if (!dm_tree_node_add_target_area(node, NULL, dlid, extent_size * seg_le(seg, s)))
|
if (!dm_tree_node_add_target_area(node, NULL, dlid, extent_size * seg_le(seg, s)))
|
||||||
return_0;
|
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)))
|
if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, lv->name, layer)))
|
||||||
return_0;
|
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))
|
if (!layer && lv_is_new_thin_pool(lv))
|
||||||
layer = lv_layer(lv);
|
layer = lv_layer(lv);
|
||||||
|
|
||||||
|
@@ -640,8 +640,8 @@ static int _process_config(struct cmd_context *cmd)
|
|||||||
if (!strcmp(cmd->stripe_filler, "/dev/ioerror") &&
|
if (!strcmp(cmd->stripe_filler, "/dev/ioerror") &&
|
||||||
stat(cmd->stripe_filler, &st))
|
stat(cmd->stripe_filler, &st))
|
||||||
cmd->stripe_filler = "error";
|
cmd->stripe_filler = "error";
|
||||||
|
else if (strcmp(cmd->stripe_filler, "error") &&
|
||||||
if (strcmp(cmd->stripe_filler, "error")) {
|
strcmp(cmd->stripe_filler, "zero")) {
|
||||||
if (stat(cmd->stripe_filler, &st)) {
|
if (stat(cmd->stripe_filler, &st)) {
|
||||||
log_warn("WARNING: activation/missing_stripe_filler = \"%s\" "
|
log_warn("WARNING: activation/missing_stripe_filler = \"%s\" "
|
||||||
"is invalid,", cmd->stripe_filler);
|
"is invalid,", cmd->stripe_filler);
|
||||||
|
@@ -94,6 +94,13 @@ struct cmd_context {
|
|||||||
struct arg_values *opt_arg_values;
|
struct arg_values *opt_arg_values;
|
||||||
struct dm_list arg_value_groups;
|
struct dm_list arg_value_groups;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Position args remaining after command name
|
||||||
|
* and --options are removed from original argc/argv.
|
||||||
|
*/
|
||||||
|
int position_argc;
|
||||||
|
char **position_argv;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Format handlers.
|
* Format handlers.
|
||||||
*/
|
*/
|
||||||
|
@@ -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,
|
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"
|
"Method to fill missing stripes when activating an incomplete LV.\n"
|
||||||
"Using 'error' will make inaccessible parts of the device return I/O\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"
|
"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"
|
"other than 'error' with mirrored or snapshotted volumes is likely to\n"
|
||||||
"result in data corruption.\n")
|
"result in data corruption.\n")
|
||||||
|
@@ -40,7 +40,7 @@ static int _extract_pattern(struct dm_pool *mem, const char *pat,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log_info("pattern must begin with 'a' or 'r'");
|
log_error("Pattern must begin with 'a' or 'r'.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
pat++;
|
pat++;
|
||||||
@@ -77,7 +77,7 @@ static int _extract_pattern(struct dm_pool *mem, const char *pat,
|
|||||||
*/
|
*/
|
||||||
ptr = r + strlen(r) - 1;
|
ptr = r + strlen(r) - 1;
|
||||||
if (*ptr != sep) {
|
if (*ptr != sep) {
|
||||||
log_info("invalid separator at end of regex");
|
log_error("Invalid separator at end of regex.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
*ptr = '\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) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -140,18 +140,18 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
|
|||||||
sector + scan_sector);
|
sector + scan_sector);
|
||||||
}
|
}
|
||||||
if (xlate64(lh->sector_xl) != sector + scan_sector) {
|
if (xlate64(lh->sector_xl) != sector + scan_sector) {
|
||||||
log_info("%s: Label for sector %" PRIu64
|
log_very_verbose("%s: Label for sector %" PRIu64
|
||||||
" found at sector %" PRIu64
|
" found at sector %" PRIu64
|
||||||
" - ignoring", dev_name(dev),
|
" - ignoring", dev_name(dev),
|
||||||
(uint64_t)xlate64(lh->sector_xl),
|
(uint64_t)xlate64(lh->sector_xl),
|
||||||
sector + scan_sector);
|
sector + scan_sector);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (calc_crc(INITIAL_CRC, (uint8_t *)&lh->offset_xl, LABEL_SIZE -
|
if (calc_crc(INITIAL_CRC, (uint8_t *)&lh->offset_xl, LABEL_SIZE -
|
||||||
((uint8_t *) &lh->offset_xl - (uint8_t *) lh)) !=
|
((uint8_t *) &lh->offset_xl - (uint8_t *) lh)) !=
|
||||||
xlate32(lh->crc_xl)) {
|
xlate32(lh->crc_xl)) {
|
||||||
log_info("Label checksum incorrect on %s - "
|
log_very_verbose("Label checksum incorrect on %s - "
|
||||||
"ignoring", dev_name(dev));
|
"ignoring", dev_name(dev));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (found)
|
if (found)
|
||||||
@@ -243,8 +243,8 @@ int label_remove(struct device *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (wipe) {
|
if (wipe) {
|
||||||
log_info("%s: Wiping label at sector %" PRIu64,
|
log_very_verbose("%s: Wiping label at sector %" PRIu64,
|
||||||
dev_name(dev), sector);
|
dev_name(dev), sector);
|
||||||
if (!dev_write(dev, sector << SECTOR_SHIFT, LABEL_SIZE,
|
if (!dev_write(dev, sector << SECTOR_SHIFT, LABEL_SIZE,
|
||||||
buf)) {
|
buf)) {
|
||||||
log_error("Failed to remove label from %s at "
|
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))
|
if (!dev_open(dev))
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
log_info("%s: Writing label to sector %" PRIu64 " with stored offset %"
|
log_very_verbose("%s: Writing label to sector %" PRIu64 " with stored offset %"
|
||||||
PRIu32 ".", dev_name(dev), label->sector,
|
PRIu32 ".", dev_name(dev), label->sector,
|
||||||
xlate32(lh->offset_xl));
|
xlate32(lh->offset_xl));
|
||||||
if (!dev_write(dev, label->sector << SECTOR_SHIFT, LABEL_SIZE, buf)) {
|
if (!dev_write(dev, label->sector << SECTOR_SHIFT, LABEL_SIZE, buf)) {
|
||||||
log_debug_devs("Failed to write label to %s", dev_name(dev));
|
log_debug_devs("Failed to write label to %s", dev_name(dev));
|
||||||
r = 0;
|
r = 0;
|
||||||
|
@@ -67,7 +67,7 @@ struct log_stream_item {
|
|||||||
char *buffer;
|
char *buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct log_stream {
|
static struct log_stream {
|
||||||
struct log_stream_item out;
|
struct log_stream_item out;
|
||||||
struct log_stream_item err;
|
struct log_stream_item err;
|
||||||
struct log_stream_item report;
|
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;
|
int bufused, n;
|
||||||
const char *trformat; /* Translated format string */
|
const char *trformat; /* Translated format string */
|
||||||
char *newbuf;
|
char *newbuf;
|
||||||
int use_stderr = level & _LOG_STDERR;
|
int use_stderr = log_stderr(level);
|
||||||
int log_once = level & _LOG_ONCE;
|
int log_once = log_once(level);
|
||||||
int log_bypass_report = level & _LOG_BYPASS_REPORT;
|
int log_bypass_report = log_bypass_report(level);
|
||||||
int fatal_internal_error = 0;
|
int fatal_internal_error = 0;
|
||||||
size_t msglen;
|
size_t msglen;
|
||||||
const char *indent_spaces = "";
|
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;
|
struct dm_report *orig_report;
|
||||||
int logged_via_report = 0;
|
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 (_abort_on_internal_errors_env_present < 0) {
|
||||||
if ((env_str = getenv("DM_ABORT_ON_INTERNAL_ERRORS"))) {
|
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
|
* LOG_WARN level and it's not going to stderr (so we're
|
||||||
* printing common message that is not an error/warning).
|
* printing common message that is not an error/warning).
|
||||||
*/
|
*/
|
||||||
if (!(level & _LOG_STDERR) &&
|
if (!log_stderr(level) &&
|
||||||
((level & ~(_LOG_STDERR|_LOG_ONCE|_LOG_BYPASS_REPORT)) == _LOG_WARN))
|
(log_level(level) == _LOG_WARN))
|
||||||
level |= _LOG_BYPASS_REPORT;
|
level |= _LOG_BYPASS_REPORT;
|
||||||
|
|
||||||
_log_stream.out.stream = report_stream;
|
_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_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_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_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: "
|
#define INTERNAL_ERROR "Internal error: "
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
* 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.
|
* 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)
|
enum activation_change activate, int needs_exclusive)
|
||||||
{
|
{
|
||||||
const char *ay_with_mode = NULL;
|
const char *ay_with_mode = NULL;
|
||||||
|
struct lv_segment *seg = first_seg(lv);
|
||||||
|
|
||||||
if (activate == CHANGE_ASY)
|
if (activate == CHANGE_ASY)
|
||||||
ay_with_mode = "sh";
|
ay_with_mode = "sh";
|
||||||
@@ -1454,6 +1455,9 @@ deactivate:
|
|||||||
break;
|
break;
|
||||||
case CHANGE_ALY:
|
case CHANGE_ALY:
|
||||||
case CHANGE_AAY:
|
case CHANGE_AAY:
|
||||||
|
if (!raid4_is_supported(cmd, seg->segtype))
|
||||||
|
goto no_raid4;
|
||||||
|
|
||||||
if (needs_exclusive || _lv_is_exclusive(lv)) {
|
if (needs_exclusive || _lv_is_exclusive(lv)) {
|
||||||
log_verbose("Activating logical volume %s exclusively locally.",
|
log_verbose("Activating logical volume %s exclusively locally.",
|
||||||
display_lvname(lv));
|
display_lvname(lv));
|
||||||
@@ -1468,6 +1472,9 @@ deactivate:
|
|||||||
break;
|
break;
|
||||||
case CHANGE_AEY:
|
case CHANGE_AEY:
|
||||||
exclusive:
|
exclusive:
|
||||||
|
if (!raid4_is_supported(cmd, seg->segtype))
|
||||||
|
goto no_raid4;
|
||||||
|
|
||||||
log_verbose("Activating logical volume %s exclusively.",
|
log_verbose("Activating logical volume %s exclusively.",
|
||||||
display_lvname(lv));
|
display_lvname(lv));
|
||||||
if (!activate_lv_excl(cmd, lv))
|
if (!activate_lv_excl(cmd, lv))
|
||||||
@@ -1476,6 +1483,9 @@ exclusive:
|
|||||||
case CHANGE_ASY:
|
case CHANGE_ASY:
|
||||||
case CHANGE_AY:
|
case CHANGE_AY:
|
||||||
default:
|
default:
|
||||||
|
if (!raid4_is_supported(cmd, seg->segtype))
|
||||||
|
goto no_raid4;
|
||||||
|
|
||||||
if (needs_exclusive || _lv_is_exclusive(lv))
|
if (needs_exclusive || _lv_is_exclusive(lv))
|
||||||
goto exclusive;
|
goto exclusive;
|
||||||
log_verbose("Activating logical volume %s.", display_lvname(lv));
|
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));
|
log_error("Failed to unlock logical volume %s.", display_lvname(lv));
|
||||||
|
|
||||||
return 1;
|
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)
|
char *lv_active_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||||
|
@@ -319,7 +319,6 @@ static int _lv_layout_and_role_thin(struct dm_pool *mem,
|
|||||||
{
|
{
|
||||||
int top_level = 0;
|
int top_level = 0;
|
||||||
unsigned snap_count;
|
unsigned snap_count;
|
||||||
struct lv_segment *seg;
|
|
||||||
|
|
||||||
/* non-top-level LVs */
|
/* non-top-level LVs */
|
||||||
if (lv_is_thin_pool_metadata(lv)) {
|
if (lv_is_thin_pool_metadata(lv)) {
|
||||||
@@ -353,7 +352,7 @@ static int _lv_layout_and_role_thin(struct dm_pool *mem,
|
|||||||
!str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_MULTITHINORIGIN]))
|
!str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_MULTITHINORIGIN]))
|
||||||
goto_bad;
|
goto_bad;
|
||||||
}
|
}
|
||||||
if ((seg = first_seg(lv)) && (seg->origin || seg->external_lv))
|
if (lv_is_thin_snapshot(lv))
|
||||||
if (!str_list_add(mem, role, _lv_type_names[LV_TYPE_SNAPSHOT]) ||
|
if (!str_list_add(mem, role, _lv_type_names[LV_TYPE_SNAPSHOT]) ||
|
||||||
!str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_THINSNAPSHOT]))
|
!str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_THINSNAPSHOT]))
|
||||||
goto_bad;
|
goto_bad;
|
||||||
@@ -3844,6 +3843,7 @@ static int _lv_extend_layered_lv(struct alloc_handle *ah,
|
|||||||
uint32_t fa, s;
|
uint32_t fa, s;
|
||||||
int clear_metadata = 0;
|
int clear_metadata = 0;
|
||||||
uint32_t area_multiple = 1;
|
uint32_t area_multiple = 1;
|
||||||
|
int fail;
|
||||||
|
|
||||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
if (!(segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||||
return_0;
|
return_0;
|
||||||
@@ -3917,45 +3917,60 @@ static int _lv_extend_layered_lv(struct alloc_handle *ah,
|
|||||||
if (!vg_write(lv->vg) || !vg_commit(lv->vg))
|
if (!vg_write(lv->vg) || !vg_commit(lv->vg))
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
for (s = 0; s < seg->area_count; s++) {
|
if (test_mode())
|
||||||
meta_lv = seg_metalv(seg, s);
|
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()) {
|
if (!activate_lv_local(meta_lv->vg->cmd, meta_lv)) {
|
||||||
lv_set_hidden(meta_lv);
|
log_error("Failed to activate %s for clearing.",
|
||||||
continue;
|
display_lvname(meta_lv));
|
||||||
|
fail = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For clearing, simply activate locally */
|
/* Clear all rmeta devices */
|
||||||
if (!activate_lv_local(meta_lv->vg->cmd, meta_lv)) {
|
for (s = 0; !fail && s < seg->area_count; s++) {
|
||||||
log_error("Failed to activate %s/%s for clearing",
|
meta_lv = seg_metalv(seg, s);
|
||||||
meta_lv->vg->name, meta_lv->name);
|
|
||||||
return 0;
|
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",
|
/* Deactivate all rmeta devices */
|
||||||
display_lvname(meta_lv));
|
for (s = 0; s < seg->area_count; s++) {
|
||||||
/*
|
meta_lv = seg_metalv(seg, s);
|
||||||
* Rather than wiping meta_lv->size, we can simply
|
|
||||||
* wipe '1' to remove the superblock of any previous
|
if (!deactivate_lv(meta_lv->vg->cmd, meta_lv)) {
|
||||||
* RAID devices. It is much quicker.
|
log_error("Failed to deactivate %s after clearing.",
|
||||||
*/
|
display_lvname(meta_lv));
|
||||||
if (!wipe_lv(meta_lv, (struct wipe_params)
|
fail = 1;
|
||||||
{ .do_zero = 1, .zero_sectors = 1 })) {
|
}
|
||||||
log_error("Failed to zero %s/%s",
|
|
||||||
meta_lv->vg->name, meta_lv->name);
|
/* Wipe any temporary tags required for activation. */
|
||||||
return 0;
|
str_list_wipe(&meta_lv->tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!deactivate_lv(meta_lv->vg->cmd, meta_lv)) {
|
if (fail)
|
||||||
log_error("Failed to deactivate %s/%s",
|
/* Fail, after trying to deactivate all we could */
|
||||||
meta_lv->vg->name, meta_lv->name);
|
return_0;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
lv_set_hidden(meta_lv);
|
|
||||||
|
|
||||||
/* Wipe any temporary tags required for activation. */
|
|
||||||
str_list_wipe(&meta_lv->tags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (s = 0; s < seg->area_count; s++)
|
||||||
|
lv_set_hidden(seg_metalv(seg, s));
|
||||||
}
|
}
|
||||||
|
|
||||||
seg->area_len += extents / area_multiple;
|
seg->area_len += extents / area_multiple;
|
||||||
|
@@ -1066,9 +1066,16 @@ struct lv_segment *get_only_segment_using_this_lv(const struct logical_volume *l
|
|||||||
* Useful functions for managing snapshots.
|
* Useful functions for managing snapshots.
|
||||||
*/
|
*/
|
||||||
int lv_is_origin(const struct logical_volume *lv);
|
int lv_is_origin(const struct logical_volume *lv);
|
||||||
|
#define lv_is_thick_origin lv_is_origin
|
||||||
|
|
||||||
int lv_is_thin_origin(const struct logical_volume *lv, unsigned *snap_count);
|
int lv_is_thin_origin(const struct logical_volume *lv, unsigned *snap_count);
|
||||||
int lv_is_cache_origin(const struct logical_volume *lv);
|
int lv_is_thin_snapshot(const struct logical_volume *lv);
|
||||||
|
|
||||||
int lv_is_cow(const struct logical_volume *lv);
|
int lv_is_cow(const struct logical_volume *lv);
|
||||||
|
#define lv_is_thick_snapshot lv_is_cow
|
||||||
|
|
||||||
|
int lv_is_cache_origin(const struct logical_volume *lv);
|
||||||
|
|
||||||
int lv_is_merging_cow(const struct logical_volume *cow);
|
int lv_is_merging_cow(const struct logical_volume *cow);
|
||||||
uint32_t cow_max_extents(const struct logical_volume *origin, uint32_t chunk_size);
|
uint32_t cow_max_extents(const struct logical_volume *origin, uint32_t chunk_size);
|
||||||
int cow_has_min_chunks(const struct volume_group *vg, uint32_t cow_extents, uint32_t chunk_size);
|
int cow_has_min_chunks(const struct volume_group *vg, uint32_t cow_extents, uint32_t chunk_size);
|
||||||
@@ -1208,8 +1215,8 @@ int lv_raid_convert(struct logical_volume *lv,
|
|||||||
const uint32_t new_region_size,
|
const uint32_t new_region_size,
|
||||||
struct dm_list *allocate_pvs);
|
struct dm_list *allocate_pvs);
|
||||||
int lv_raid_rebuild(struct logical_volume *lv, struct dm_list *rebuild_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,
|
int lv_raid_replace(struct logical_volume *lv, int force,
|
||||||
struct dm_list *allocate_pvs);
|
struct dm_list *remove_pvs, struct dm_list *allocate_pvs);
|
||||||
int lv_raid_remove_missing(struct logical_volume *lv);
|
int lv_raid_remove_missing(struct logical_volume *lv);
|
||||||
int partial_raid_lv_supports_degraded_activation(const struct logical_volume *lv);
|
int partial_raid_lv_supports_degraded_activation(const struct logical_volume *lv);
|
||||||
/* -- metadata/raid_manip.c */
|
/* -- 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.
|
* Returns: 1 if in-sync, 0 otherwise.
|
||||||
*/
|
*/
|
||||||
|
#define _RAID_IN_SYNC_RETRIES 6
|
||||||
static int _raid_in_sync(struct logical_volume *lv)
|
static int _raid_in_sync(struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
|
int retries = _RAID_IN_SYNC_RETRIES;
|
||||||
dm_percent_t sync_percent;
|
dm_percent_t sync_percent;
|
||||||
|
|
||||||
if (seg_is_striped(first_seg(lv)))
|
if (seg_is_striped(first_seg(lv)))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (!lv_raid_percent(lv, &sync_percent)) {
|
do {
|
||||||
log_error("Unable to determine sync status of %s/%s.",
|
|
||||||
lv->vg->name, lv->name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (sync_percent == DM_PERCENT_0) {
|
|
||||||
/*
|
/*
|
||||||
* FIXME We repeat the status read here to workaround an
|
* FIXME We repeat the status read here to workaround an
|
||||||
* unresolved kernel bug when we see 0 even though the
|
* 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);
|
lv->vg->name, lv->name);
|
||||||
return 0;
|
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.",
|
log_warn("WARNING: Sync status for %s is inconsistent.",
|
||||||
display_lvname(lv));
|
display_lvname(lv));
|
||||||
}
|
usleep(500000);
|
||||||
|
} while (--retries);
|
||||||
|
|
||||||
return (sync_percent == DM_PERCENT_100) ? 1 : 0;
|
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
|
* _raid_remove_top_layer
|
||||||
* @lv
|
* @lv
|
||||||
@@ -1038,11 +1055,10 @@ static int _extract_image_components(struct lv_segment *seg, uint32_t idx,
|
|||||||
seg_type(seg, idx) = AREA_UNASSIGNED;
|
seg_type(seg, idx) = AREA_UNASSIGNED;
|
||||||
seg_metatype(seg, idx) = AREA_UNASSIGNED;
|
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;
|
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;
|
return_0;
|
||||||
|
|
||||||
*extracted_rmeta = meta_lv;
|
*extracted_rmeta = meta_lv;
|
||||||
@@ -1054,6 +1070,7 @@ static int _extract_image_components(struct lv_segment *seg, uint32_t idx,
|
|||||||
/*
|
/*
|
||||||
* _raid_extract_images
|
* _raid_extract_images
|
||||||
* @lv
|
* @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)
|
* @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
|
* @target_pvs: The list of PVs that are candidates for removal
|
||||||
* @shift: If set, use _shift_and_rename_image_components().
|
* @shift: If set, use _shift_and_rename_image_components().
|
||||||
@@ -1068,7 +1085,8 @@ static int _extract_image_components(struct lv_segment *seg, uint32_t idx,
|
|||||||
*
|
*
|
||||||
* Returns: 1 on success, 0 on failure
|
* 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 *target_pvs, int shift,
|
||||||
struct dm_list *extracted_meta_lvs,
|
struct dm_list *extracted_meta_lvs,
|
||||||
struct dm_list *extracted_data_lvs)
|
struct dm_list *extracted_data_lvs)
|
||||||
@@ -1136,11 +1154,16 @@ static int _raid_extract_images(struct logical_volume *lv, uint32_t new_count,
|
|||||||
!lv_is_on_pvs(seg_metalv(seg, s), target_pvs))
|
!lv_is_on_pvs(seg_metalv(seg, s), target_pvs))
|
||||||
continue;
|
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"
|
log_error("Unable to extract %sRAID image"
|
||||||
" while RAID array is not in-sync",
|
" while RAID array is not in-sync%s",
|
||||||
seg_is_mirrored(seg) ? "primary " : "");
|
seg_is_mirrored(seg) ? "primary " : "",
|
||||||
|
seg_is_mirrored(seg) ? " (use --force option to replace)" : "");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1185,7 +1208,7 @@ static int _raid_remove_images(struct logical_volume *lv,
|
|||||||
if (!removal_lvs)
|
if (!removal_lvs)
|
||||||
removal_lvs = &removed_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)) {
|
removal_lvs, removal_lvs)) {
|
||||||
log_error("Failed to extract images from %s/%s",
|
log_error("Failed to extract images from %s/%s",
|
||||||
lv->vg->name, lv->name);
|
lv->vg->name, lv->name);
|
||||||
@@ -1375,7 +1398,7 @@ int lv_raid_split(struct logical_volume *lv, const char *split_name,
|
|||||||
return_0;
|
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)) {
|
&removal_lvs, &data_list)) {
|
||||||
log_error("Failed to extract images from %s/%s",
|
log_error("Failed to extract images from %s/%s",
|
||||||
lv->vg->name, lv->name);
|
lv->vg->name, lv->name);
|
||||||
@@ -2459,7 +2482,7 @@ static struct lv_segment *_convert_striped_to_raid0(struct logical_volume *lv,
|
|||||||
0 /* chunk_size */,
|
0 /* chunk_size */,
|
||||||
0 /* seg->region_size */, 0u /* extents_copied */ ,
|
0 /* seg->region_size */, 0u /* extents_copied */ ,
|
||||||
NULL /* pvmove_source_seg */))) {
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2519,42 +2542,51 @@ static struct possible_takeover_reshape_type _possible_takeover_reshape_types[]
|
|||||||
{ .current_types = SEG_STRIPED_TARGET, /* linear, i.e. seg->area_count = 1 */
|
{ .current_types = SEG_STRIPED_TARGET, /* linear, i.e. seg->area_count = 1 */
|
||||||
.possible_types = SEG_RAID1,
|
.possible_types = SEG_RAID1,
|
||||||
.current_areas = 1,
|
.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 */
|
{ .current_types = SEG_STRIPED_TARGET, /* linear, i.e. seg->area_count = 1 */
|
||||||
.possible_types = SEG_RAID0|SEG_RAID0_META,
|
.possible_types = SEG_RAID0|SEG_RAID0_META,
|
||||||
.current_areas = 1,
|
.current_areas = 1,
|
||||||
.options = ALLOW_STRIPE_SIZE },
|
.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,
|
.possible_types = SEG_RAID0|SEG_RAID0_META,
|
||||||
.current_areas = ~0U,
|
.current_areas = ~0U,
|
||||||
.options = ALLOW_NONE },
|
.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* -> */
|
/* raid0* -> */
|
||||||
{ .current_types = SEG_RAID0|SEG_RAID0_META, /* seg->area_count = 1 */
|
{ .current_types = SEG_RAID0|SEG_RAID0_META, /* seg->area_count = 1 */
|
||||||
.possible_types = SEG_RAID1,
|
.possible_types = SEG_RAID1,
|
||||||
.current_areas = 1,
|
.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 },
|
.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,
|
.possible_types = SEG_RAID4,
|
||||||
.current_areas = ~0U,
|
.current_areas = ~0U,
|
||||||
.options = ALLOW_NONE },
|
.options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
|
||||||
{ .current_types = SEG_RAID0|SEG_RAID0_META, /* raid0 striped, i.e. seg->area_count > 0 */
|
/* raid4 -> -> */
|
||||||
|
{ .current_types = SEG_RAID4, /* raid4 ->striped/raid0*, i.e. seg->area_count > 1 */
|
||||||
.possible_types = SEG_STRIPED_TARGET|SEG_RAID0|SEG_RAID0_META,
|
.possible_types = SEG_STRIPED_TARGET|SEG_RAID0|SEG_RAID0_META,
|
||||||
.current_areas = ~0U,
|
.current_areas = ~0U,
|
||||||
.options = ALLOW_NONE },
|
.options = ALLOW_NONE },
|
||||||
/* raid1 -> */
|
/* raid1 -> mirror */
|
||||||
{ .current_types = SEG_RAID1,
|
{ .current_types = SEG_RAID1,
|
||||||
.possible_types = SEG_RAID1|SEG_MIRROR,
|
.possible_types = SEG_MIRROR,
|
||||||
.current_areas = ~0U,
|
.current_areas = ~0U,
|
||||||
.options = ALLOW_NONE },
|
.options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
|
||||||
/* mirror -> raid1 with arbitrary number of legs */
|
/* mirror -> raid1 with arbitrary number of legs */
|
||||||
{ .current_types = SEG_MIRROR,
|
{ .current_types = SEG_MIRROR,
|
||||||
.possible_types = SEG_MIRROR|SEG_RAID1,
|
.possible_types = SEG_RAID1,
|
||||||
.current_areas = ~0U,
|
.current_areas = ~0U,
|
||||||
.options = ALLOW_NONE },
|
.options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
|
||||||
{ .current_types = SEG_RAID4,
|
|
||||||
.possible_types = SEG_STRIPED_TARGET|SEG_RAID0|SEG_RAID0_META,
|
|
||||||
.current_areas = ~0U,
|
|
||||||
.options = ALLOW_NONE },
|
|
||||||
|
|
||||||
/* END */
|
/* END */
|
||||||
{ .current_types = 0 }
|
{ .current_types = 0 }
|
||||||
@@ -2861,9 +2893,176 @@ static int _raid1_to_mirrored_wrapper(TAKEOVER_FN_ARGS)
|
|||||||
allocate_pvs, 1, &removal_lvs);
|
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 */
|
/* raid45 -> raid0* / striped */
|
||||||
static int _raid456_to_raid0_or_striped_wrapper(TAKEOVER_FN_ARGS)
|
static int _raid456_to_raid0_or_striped_wrapper(TAKEOVER_FN_ARGS)
|
||||||
{
|
{
|
||||||
|
int rename_sublvs = 0;
|
||||||
struct lv_segment *seg = first_seg(lv);
|
struct lv_segment *seg = first_seg(lv);
|
||||||
struct dm_list removal_lvs;
|
struct dm_list removal_lvs;
|
||||||
|
|
||||||
@@ -2879,10 +3078,39 @@ static int _raid456_to_raid0_or_striped_wrapper(TAKEOVER_FN_ARGS)
|
|||||||
if (!_raid_in_sync(lv))
|
if (!_raid_in_sync(lv))
|
||||||
return 0;
|
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 */
|
/* Archive metadata */
|
||||||
if (!archive(lv->vg))
|
if (!archive(lv->vg))
|
||||||
return_0;
|
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 */
|
/* Remove meta and data LVs requested */
|
||||||
if (!_lv_raid_change_image_count(lv, new_image_count, allocate_pvs, &removal_lvs, 0, 0))
|
if (!_lv_raid_change_image_count(lv, new_image_count, allocate_pvs, &removal_lvs, 0, 0))
|
||||||
return 0;
|
return 0;
|
||||||
@@ -2902,7 +3130,19 @@ static int _raid456_to_raid0_or_striped_wrapper(TAKEOVER_FN_ARGS)
|
|||||||
|
|
||||||
seg->region_size = 0;
|
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,
|
static int _striped_to_raid0_wrapper(struct logical_volume *lv,
|
||||||
@@ -2930,6 +3170,9 @@ static int _striped_to_raid0_wrapper(struct logical_volume *lv,
|
|||||||
static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS)
|
static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS)
|
||||||
{
|
{
|
||||||
struct lv_segment *seg = first_seg(lv);
|
struct lv_segment *seg = first_seg(lv);
|
||||||
|
struct dm_list removal_lvs;
|
||||||
|
|
||||||
|
dm_list_init(&removal_lvs);
|
||||||
|
|
||||||
if (seg_is_raid10(seg))
|
if (seg_is_raid10(seg))
|
||||||
return _takeover_unsupported_yet(lv, new_stripes, new_segtype);
|
return _takeover_unsupported_yet(lv, new_stripes, new_segtype);
|
||||||
@@ -2944,6 +3187,13 @@ static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS)
|
|||||||
return 0;
|
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 */
|
/* Archive metadata */
|
||||||
if (!archive(lv->vg))
|
if (!archive(lv->vg))
|
||||||
return_0;
|
return_0;
|
||||||
@@ -2961,7 +3211,10 @@ static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS)
|
|||||||
log_debug_metadata("Adding metadata LVs to %s", display_lvname(lv));
|
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))
|
if (!_raid0_add_or_remove_metadata_lvs(lv, 1 /* update_and_reload */, allocate_pvs, NULL))
|
||||||
return 0;
|
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 */
|
/* 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),
|
log_debug_metadata("Adding %" PRIu32 " component LV pair(s) to %s", new_image_count - lv_raid_image_count(lv),
|
||||||
@@ -2969,8 +3222,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))
|
if (!_lv_raid_change_image_count(lv, new_image_count, allocate_pvs, NULL, 0, 1))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!segtype_is_raid4(new_segtype)) {
|
if (segtype_is_raid4(new_segtype) &&
|
||||||
/* Can't convert striped/raid0* to e.g. raid10_offset */
|
(!_shift_parity_dev(seg) ||
|
||||||
|
!_rename_area_lvs(lv, "_"))) {
|
||||||
log_error("Can't convert %s to %s", display_lvname(lv), new_segtype->name);
|
log_error("Can't convert %s to %s", display_lvname(lv), new_segtype->name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -2987,6 +3241,14 @@ static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS)
|
|||||||
if (!_lv_update_reload_fns_reset_eliminate_lvs(lv, NULL))
|
if (!_lv_update_reload_fns_reset_eliminate_lvs(lv, NULL))
|
||||||
return_0;
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3630,6 +3892,7 @@ has_enough_space:
|
|||||||
* new SubLVS are allocated on PVs on list @allocate_pvs.
|
* new SubLVS are allocated on PVs on list @allocate_pvs.
|
||||||
*/
|
*/
|
||||||
static int _lv_raid_rebuild_or_replace(struct logical_volume *lv,
|
static int _lv_raid_rebuild_or_replace(struct logical_volume *lv,
|
||||||
|
int force,
|
||||||
struct dm_list *remove_pvs,
|
struct dm_list *remove_pvs,
|
||||||
struct dm_list *allocate_pvs,
|
struct dm_list *allocate_pvs,
|
||||||
int rebuild)
|
int rebuild)
|
||||||
@@ -3804,7 +4067,8 @@ try_again:
|
|||||||
* supplied - knowing that only the image with the error target
|
* supplied - knowing that only the image with the error target
|
||||||
* will be affected.
|
* 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 ?
|
partial_segment_removed ?
|
||||||
&lv->vg->pvs : remove_pvs, 0,
|
&lv->vg->pvs : remove_pvs, 0,
|
||||||
&old_lvs, &old_lvs)) {
|
&old_lvs, &old_lvs)) {
|
||||||
@@ -3909,7 +4173,7 @@ skip_alloc:
|
|||||||
int lv_raid_rebuild(struct logical_volume *lv,
|
int lv_raid_rebuild(struct logical_volume *lv,
|
||||||
struct dm_list *rebuild_pvs)
|
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 +4186,11 @@ int lv_raid_rebuild(struct logical_volume *lv,
|
|||||||
* allocating new SubLVs from PVs on list @allocate_pvs.
|
* allocating new SubLVs from PVs on list @allocate_pvs.
|
||||||
*/
|
*/
|
||||||
int lv_raid_replace(struct logical_volume *lv,
|
int lv_raid_replace(struct logical_volume *lv,
|
||||||
|
int force,
|
||||||
struct dm_list *remove_pvs,
|
struct dm_list *remove_pvs,
|
||||||
struct dm_list *allocate_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)
|
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) 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.
|
* 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_RAID10 (1U << 0) /* version 1.3 */
|
||||||
#define RAID_FEATURE_RAID0 (1U << 1) /* version 1.7 */
|
#define RAID_FEATURE_RAID0 (1U << 1) /* version 1.7 */
|
||||||
#define RAID_FEATURE_RESHAPING (1U << 2) /* version 1.8 */
|
#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
|
#ifdef RAID_INTERNAL
|
||||||
int init_raid_segtypes(struct cmd_context *cmd, struct segtype_library *seglib);
|
int init_raid_segtypes(struct cmd_context *cmd, struct segtype_library *seglib);
|
||||||
|
@@ -748,6 +748,19 @@ int lv_is_thin_origin(const struct logical_volume *lv, unsigned int *snap_count)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int lv_is_thin_snapshot(const struct logical_volume *lv)
|
||||||
|
{
|
||||||
|
struct lv_segment *seg;
|
||||||
|
|
||||||
|
if (!lv_is_thin_volume(lv))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if ((seg = first_seg(lv)) && (seg->origin || seg->external_lv))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Explict check of new thin pool for usability
|
* Explict check of new thin pool for usability
|
||||||
*
|
*
|
||||||
|
@@ -15,6 +15,8 @@
|
|||||||
#define LVM_DBUS_DESTINATION "com.redhat.lvmdbus1"
|
#define LVM_DBUS_DESTINATION "com.redhat.lvmdbus1"
|
||||||
#define LVM_DBUS_PATH "/com/redhat/lvmdbus1/Manager"
|
#define LVM_DBUS_PATH "/com/redhat/lvmdbus1/Manager"
|
||||||
#define LVM_DBUS_INTERFACE "com.redhat.lvmdbus1.Manager"
|
#define LVM_DBUS_INTERFACE "com.redhat.lvmdbus1.Manager"
|
||||||
|
#define SD_BUS_SYSTEMD_NO_SUCH_UNIT_ERROR "org.freedesktop.systemd1.NoSuchUnit"
|
||||||
|
#define SD_BUS_DBUS_SERVICE_UNKNOWN_ERROR "org.freedesktop.DBus.Error.ServiceUnknown"
|
||||||
|
|
||||||
#ifdef NOTIFYDBUS_SUPPORT
|
#ifdef NOTIFYDBUS_SUPPORT
|
||||||
#include <systemd/sd-bus.h>
|
#include <systemd/sd-bus.h>
|
||||||
@@ -26,6 +28,7 @@ int lvmnotify_is_supported(void)
|
|||||||
|
|
||||||
void lvmnotify_send(struct cmd_context *cmd)
|
void lvmnotify_send(struct cmd_context *cmd)
|
||||||
{
|
{
|
||||||
|
static const char _dbus_notification_failed_msg[] = "D-Bus notification failed";
|
||||||
sd_bus *bus = NULL;
|
sd_bus *bus = NULL;
|
||||||
sd_bus_message *m = NULL;
|
sd_bus_message *m = NULL;
|
||||||
sd_bus_error error = SD_BUS_ERROR_NULL;
|
sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||||
@@ -61,7 +64,11 @@ void lvmnotify_send(struct cmd_context *cmd)
|
|||||||
cmd_name);
|
cmd_name);
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
log_warn("WARNING: D-Bus notification failed: %s", error.message);
|
if (sd_bus_error_has_name(&error, SD_BUS_SYSTEMD_NO_SUCH_UNIT_ERROR) ||
|
||||||
|
sd_bus_error_has_name(&error, SD_BUS_DBUS_SERVICE_UNKNOWN_ERROR))
|
||||||
|
log_debug_dbus("%s: %s", _dbus_notification_failed_msg, error.message);
|
||||||
|
else
|
||||||
|
log_warn("WARNING: %s: %s", _dbus_notification_failed_msg, error.message);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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.
|
* 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_checked = 0;
|
||||||
static int _raid_present = 0;
|
static int _raid_present = 0;
|
||||||
static int _raid_attrs = 0;
|
static unsigned _raid_attrs = 0;
|
||||||
uint32_t maj, min, patchlevel;
|
uint32_t maj, min, patchlevel;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
@@ -389,6 +389,12 @@ static int _raid_target_present(struct cmd_context *cmd,
|
|||||||
else
|
else
|
||||||
log_very_verbose("Target raid does not support %s.",
|
log_very_verbose("Target raid does not support %s.",
|
||||||
_features[i].feature);
|
_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)
|
if (attributes)
|
||||||
|
@@ -114,9 +114,9 @@ static void _default_log_line(int level,
|
|||||||
const char *f, va_list ap)
|
const char *f, va_list ap)
|
||||||
{
|
{
|
||||||
static int _abort_on_internal_errors = -1;
|
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 || _verbose) {
|
||||||
if (level < _LOG_WARN)
|
if (level < _LOG_WARN)
|
||||||
@@ -137,8 +137,7 @@ static void _default_log_line(int level,
|
|||||||
|
|
||||||
__attribute__((format(printf, 5, 6)))
|
__attribute__((format(printf, 5, 6)))
|
||||||
static void _default_log_with_errno(int level,
|
static void _default_log_with_errno(int level,
|
||||||
const char *file __attribute__((unused)),
|
const char *file, int line, int dm_errno_or_class,
|
||||||
int line __attribute__((unused)), int dm_errno_or_class,
|
|
||||||
const char *f, ...)
|
const char *f, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
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_fn dm_log = _default_log;
|
||||||
dm_log_with_errno_fn dm_log_with_errno = _default_log_with_errno;
|
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)
|
void dm_log_init(dm_log_fn fn)
|
||||||
{
|
{
|
||||||
if (fn)
|
if (fn) {
|
||||||
dm_log = fn;
|
dm_log = fn;
|
||||||
else
|
dm_log_with_errno = _log_to_default_log;
|
||||||
|
} else {
|
||||||
dm_log = _default_log;
|
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)
|
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)
|
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;
|
dm_log_with_errno = fn;
|
||||||
else
|
} else {
|
||||||
|
dm_log = _default_log;
|
||||||
dm_log_with_errno = _default_log_with_errno;
|
dm_log_with_errno = _default_log_with_errno;
|
||||||
|
}
|
||||||
dm_log = _default_log;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dm_log_init_verbose(int level)
|
void dm_log_init_verbose(int level)
|
||||||
|
@@ -3881,7 +3881,7 @@ merge:
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (_extents_overlap(ext, next)) {
|
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 "
|
FMTu64 " overlap. Some events will be "
|
||||||
"counted twice.", ext->id, next->id);
|
"counted twice.", ext->id, next->id);
|
||||||
/* merge larger extent into smaller */
|
/* 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))
|
if (precise && (precise != count))
|
||||||
log_warn("Grouping regions with different clock resolution: "
|
log_warn("WARNING: Grouping regions with different clock resolution: "
|
||||||
"precision may be lost");
|
"precision may be lost.");
|
||||||
|
|
||||||
if (!_stats_group_check_overlap(dms, regions, count))
|
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))
|
if (!_stats_create_group(dms, regions, alias, group_id))
|
||||||
goto bad;
|
goto bad;
|
||||||
@@ -4048,7 +4048,7 @@ int dm_stats_delete_group(struct dm_stats *dms, uint64_t group_id,
|
|||||||
if (dm_bit(regions, i)) {
|
if (dm_bit(regions, i)) {
|
||||||
dm_bit_clear(regions, i);
|
dm_bit_clear(regions, i);
|
||||||
if (remove_regions && !dm_stats_delete_region(dms, 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);
|
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.
|
* returned by FIEMAP imply a kernel bug or a corrupt fs.
|
||||||
*/
|
*/
|
||||||
if (!_stats_group_check_overlap(dms, regions, count))
|
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))
|
if (!_stats_create_group(dms, regions, alias, &group_id))
|
||||||
goto bad;
|
goto bad;
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
* 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.
|
* This file is part of LVM2.
|
||||||
*
|
*
|
||||||
@@ -18,16 +18,10 @@
|
|||||||
|
|
||||||
#include "libdevmapper.h"
|
#include "libdevmapper.h"
|
||||||
|
|
||||||
extern dm_log_fn dm_log;
|
|
||||||
extern dm_log_with_errno_fn dm_log_with_errno;
|
extern dm_log_with_errno_fn dm_log_with_errno;
|
||||||
|
|
||||||
#define LOG_MESG(l, f, ln, e, x...) \
|
#define LOG_MESG(l, f, ln, e, x...) \
|
||||||
do { \
|
dm_log_with_errno(l, f, ln, e, ## x)
|
||||||
if (dm_log_is_non_default()) \
|
|
||||||
dm_log(l, f, ln, ## x); \
|
|
||||||
else \
|
|
||||||
dm_log_with_errno(l, f, ln, e, ## x); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define LOG_LINE(l, x...) LOG_MESG(l, __FILE__, __LINE__, 0, ## x)
|
#define LOG_LINE(l, x...) LOG_MESG(l, __FILE__, __LINE__, 0, ## x)
|
||||||
#define LOG_LINE_WITH_ERRNO(l, e, x...) LOG_MESG(l, __FILE__, __LINE__, e, ## 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
|
VG/RaidLV
|
||||||
.br
|
.br
|
||||||
\[bu]
|
\[bu]
|
||||||
|
Options \-\-background, \-\-interval.
|
||||||
|
.br
|
||||||
|
\[bu]
|
||||||
Replace failed PVs in RaidLV.
|
Replace failed PVs in RaidLV.
|
||||||
|
|
||||||
.B lvconvert \-\-replace
|
.B lvconvert \-\-replace
|
||||||
@@ -502,6 +505,9 @@ Change the type of log used by MirrorLV.
|
|||||||
VG/MirrorLV
|
VG/MirrorLV
|
||||||
.br
|
.br
|
||||||
\[bu]
|
\[bu]
|
||||||
|
Options \-\-background, \-\-interval.
|
||||||
|
.br
|
||||||
|
\[bu]
|
||||||
Replace failed PVs in MirrorLV.
|
Replace failed PVs in MirrorLV.
|
||||||
|
|
||||||
.B lvconvert \-\-type linear
|
.B lvconvert \-\-type linear
|
||||||
|
@@ -34,6 +34,7 @@ TOOL=blkdeactivate
|
|||||||
DEV_DIR='/dev'
|
DEV_DIR='/dev'
|
||||||
SYS_BLK_DIR='/sys/block'
|
SYS_BLK_DIR='/sys/block'
|
||||||
|
|
||||||
|
MOUNTPOINT="/bin/mountpoint"
|
||||||
UMOUNT="/bin/umount"
|
UMOUNT="/bin/umount"
|
||||||
DMSETUP="@sbindir@/dmsetup"
|
DMSETUP="@sbindir@/dmsetup"
|
||||||
LVM="@sbindir@/lvm"
|
LVM="@sbindir@/lvm"
|
||||||
@@ -157,9 +158,11 @@ device_umount_one() {
|
|||||||
echo -n " [UMOUNT]: unmounting $name ($kname) mounted on $mnt... "
|
echo -n " [UMOUNT]: unmounting $name ($kname) mounted on $mnt... "
|
||||||
if eval $UMOUNT $UMOUNT_OPTS "$(printf "%s" "$mnt")" $OUT $ERR; then
|
if eval $UMOUNT $UMOUNT_OPTS "$(printf "%s" "$mnt")" $OUT $ERR; then
|
||||||
echo "done"
|
echo "done"
|
||||||
else
|
elif $MOUNTPOINT -q "$mnt"; then
|
||||||
echo "skipping"
|
echo "skipping"
|
||||||
add_device_to_skip_list
|
add_device_to_skip_list
|
||||||
|
else
|
||||||
|
echo "already unmounted"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo " [SKIP]: unmount of $name ($kname) mounted on $mnt"
|
echo " [SKIP]: unmount of $name ($kname) mounted on $mnt"
|
||||||
|
@@ -77,6 +77,9 @@ help:
|
|||||||
@echo " check_cluster Run tests with cluster daemon."
|
@echo " check_cluster Run tests with cluster daemon."
|
||||||
@echo " check_lvmetad Run tests with lvmetad daemon."
|
@echo " check_lvmetad Run tests with lvmetad daemon."
|
||||||
@echo " check_lvmpolld Run tests with lvmpolld 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_sanlock Run tests with lvmlockd and sanlock."
|
||||||
@echo " check_lvmlockd_dlm Run tests with lvmlockd and dlm."
|
@echo " check_lvmlockd_dlm Run tests with lvmlockd and dlm."
|
||||||
@echo " check_lvmlockd_test Run tests with lvmlockd --test."
|
@echo " check_lvmlockd_test Run tests with lvmlockd --test."
|
||||||
@@ -144,6 +147,21 @@ endif
|
|||||||
|
|
||||||
ifeq ("@BUILD_LVMPOLLD@", "yes")
|
ifeq ("@BUILD_LVMPOLLD@", "yes")
|
||||||
check_lvmpolld: .tests-stamp
|
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 \
|
VERBOSE=$(VERBOSE) ./lib/runner \
|
||||||
--testdir . --outdir results \
|
--testdir . --outdir results \
|
||||||
--flavours ndev-lvmpolld,ndev-cluster-lvmpolld,ndev-lvmetad-lvmpolld --only $(T) --skip $(S)
|
--flavours ndev-lvmpolld,ndev-cluster-lvmpolld,ndev-lvmetad-lvmpolld --only $(T) --skip $(S)
|
||||||
|
@@ -1063,7 +1063,7 @@ generate_config() {
|
|||||||
cat > "$config_values" <<-EOF
|
cat > "$config_values" <<-EOF
|
||||||
activation/checks = 1
|
activation/checks = 1
|
||||||
activation/monitoring = 0
|
activation/monitoring = 0
|
||||||
activation/polling_interval = 0
|
activation/polling_interval = 1
|
||||||
activation/retry_deactivation = 1
|
activation/retry_deactivation = 1
|
||||||
activation/snapshot_autoextend_percent = 50
|
activation/snapshot_autoextend_percent = 50
|
||||||
activation/snapshot_autoextend_threshold = 50
|
activation/snapshot_autoextend_threshold = 50
|
||||||
@@ -1376,6 +1376,15 @@ have_raid() {
|
|||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
have_raid4 () {
|
||||||
|
local r=1
|
||||||
|
|
||||||
|
have_raid 1 8 0 && r=0
|
||||||
|
have_raid 1 9 1 && r=1
|
||||||
|
|
||||||
|
return $r
|
||||||
|
}
|
||||||
|
|
||||||
have_cache() {
|
have_cache() {
|
||||||
test "$CACHE" = shared -o "$CACHE" = internal || {
|
test "$CACHE" = shared -o "$CACHE" = internal || {
|
||||||
echo "Cache is not built-in." >&2
|
echo "Cache is not built-in." >&2
|
||||||
|
@@ -16,7 +16,7 @@ TEST_RAID=raid456
|
|||||||
aux raid456_replace_works || skip
|
aux raid456_replace_works || skip
|
||||||
aux have_raid 1 5 2 || 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 raid5 -i 2 "$dev1" "$dev2" "$dev3" "$dev4"
|
||||||
run_types raid6 -i 3 "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
|
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
|
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
|
aux prepare_vg 9 288
|
||||||
|
|
||||||
# Delay 1st leg so that rebuilding status characters
|
# Delay 1st leg so that rebuilding status characters
|
||||||
@@ -78,22 +81,61 @@ aux wait_for_sync $vg $lv1
|
|||||||
# Clean up
|
# Clean up
|
||||||
lvremove --yes $vg/$lv1
|
lvremove --yes $vg/$lv1
|
||||||
|
|
||||||
# Create 3-way raid0
|
# Create 3-way striped
|
||||||
lvcreate -y -aey --type raid0 -i 3 -L 64M -n $lv1 $vg
|
lvcreate -y -aey --type striped -i 3 -L 64M -n $lv1 $vg
|
||||||
check lv_field $vg/$lv1 segtype "raid0"
|
check lv_field $vg/$lv1 segtype "striped"
|
||||||
check lv_field $vg/$lv1 stripes 3
|
check lv_field $vg/$lv1 stripes 3
|
||||||
echo y | mkfs -t ext4 /dev/mapper/$vg-$lv1
|
echo y | mkfs -t ext4 /dev/mapper/$vg-$lv1
|
||||||
fsck -fn /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
|
lvconvert -y --ty raid4 $vg/$lv1
|
||||||
lvchange --refresh $vg/$lv1
|
|
||||||
check lv_field $vg/$lv1 segtype "raid4"
|
check lv_field $vg/$lv1 segtype "raid4"
|
||||||
check lv_field $vg/$lv1 stripes 4
|
check lv_field $vg/$lv1 stripes 4
|
||||||
fsck -fn /dev/mapper/$vg-$lv1
|
fsck -fn /dev/mapper/$vg-$lv1
|
||||||
aux wait_for_sync $vg $lv1
|
aux wait_for_sync $vg $lv1
|
||||||
fsck -fn /dev/mapper/$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
|
# Convert raid4 -> raid0_meta
|
||||||
lvconvert -y --ty raid0_meta $vg/$lv1
|
lvconvert -y --ty raid0_meta $vg/$lv1
|
||||||
check lv_field $vg/$lv1 segtype "raid0_meta"
|
check lv_field $vg/$lv1 segtype "raid0_meta"
|
||||||
@@ -116,11 +158,24 @@ fsck -fn /dev/mapper/$vg-$lv1
|
|||||||
|
|
||||||
# Convert raid0 -> raid4
|
# Convert raid0 -> raid4
|
||||||
lvconvert -y --ty raid4 $vg/$lv1
|
lvconvert -y --ty raid4 $vg/$lv1
|
||||||
lvchange --refresh $vg/$lv1
|
|
||||||
check lv_field $vg/$lv1 segtype "raid4"
|
check lv_field $vg/$lv1 segtype "raid4"
|
||||||
check lv_field $vg/$lv1 stripes 4
|
check lv_field $vg/$lv1 stripes 4
|
||||||
fsck -fn /dev/mapper/$vg-$lv1
|
fsck -fn /dev/mapper/$vg-$lv1
|
||||||
aux wait_for_sync $vg $lv1
|
aux wait_for_sync $vg $lv1
|
||||||
fsck -fn /dev/mapper/$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
|
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
|
aux prepare_pvs 7 # 7 devices for 2 dev replacement of 5-dev RAID6
|
||||||
vgcreate -s 256k $vg $(cat DEVICES)
|
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)
|
# 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
|
lvcreate --type raid$i -i 3 -l 3 -n $lv1 $vg
|
||||||
|
|
||||||
if [ $i -eq 6 ]; then
|
if [ $i -eq 6 ]; then
|
||||||
|
@@ -25,7 +25,8 @@ which "$FSCK" || skip
|
|||||||
#
|
#
|
||||||
# Main
|
# 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
|
aux prepare_vg 4
|
||||||
|
|
||||||
|
@@ -53,7 +53,8 @@ delay 50
|
|||||||
# RAID1 triple-leg single replace during initial sync
|
# RAID1 triple-leg single replace during initial sync
|
||||||
lvcreate --type raid1 -m 2 -L $RAID_SIZE -n $lv1 $vg "$dev1" "$dev2" "$dev3"
|
lvcreate --type raid1 -m 2 -L $RAID_SIZE -n $lv1 $vg "$dev1" "$dev2" "$dev3"
|
||||||
aux disable_dev "$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
|
aux wait_for_sync $vg $lv1
|
||||||
lvconvert -y --repair $vg/$lv1
|
lvconvert -y --repair $vg/$lv1
|
||||||
vgreduce --removemissing $vg
|
vgreduce --removemissing $vg
|
||||||
|
@@ -21,6 +21,9 @@ aux can_use_16T || skip
|
|||||||
|
|
||||||
aux have_raid 1 3 0 || skip
|
aux have_raid 1 3 0 || skip
|
||||||
|
|
||||||
|
segtypes="raid5"
|
||||||
|
aux have_raid4 && segtypes="raid4 raid5"
|
||||||
|
|
||||||
# Prepare 5x ~1P sized devices
|
# Prepare 5x ~1P sized devices
|
||||||
aux prepare_pvs 5 1000000000
|
aux prepare_pvs 5 1000000000
|
||||||
|
|
||||||
@@ -53,7 +56,7 @@ check raid_leg_status $vg1 $lv1 "AA"
|
|||||||
lvremove -ff $vg1
|
lvremove -ff $vg1
|
||||||
|
|
||||||
# 750 TiB raid4/5
|
# 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
|
lvcreate --type $segtype -i 3 -L 750T -n $lv1 $vg1 --nosync
|
||||||
check lv_field $vg1/$lv1 size "750.00t"
|
check lv_field $vg1/$lv1 size "750.00t"
|
||||||
check raid_leg_status $vg1 $lv1 "AAAA"
|
check raid_leg_status $vg1 $lv1 "AAAA"
|
||||||
|
@@ -16,17 +16,20 @@ SKIP_WITH_LVMPOLLD=1
|
|||||||
|
|
||||||
aux have_raid 1 7 0 || skip
|
aux have_raid 1 7 0 || skip
|
||||||
|
|
||||||
|
segtypes=raid5
|
||||||
|
aux have_raid4 && segtypes="raid4 raid5"
|
||||||
|
|
||||||
aux prepare_vg 6
|
aux prepare_vg 6
|
||||||
|
|
||||||
|
|
||||||
# Delay 1st leg so that rebuilding status characters
|
# Delay 1st leg so that rebuilding status characters
|
||||||
# can be read before resync finished too quick.
|
# 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
|
# raid0/raid0_meta don't support resynchronization
|
||||||
for r in raid0 raid0_meta
|
for r in raid0 raid0_meta
|
||||||
do
|
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"
|
check raid_leg_status $vg $lv1 "AAA"
|
||||||
lvremove --yes $vg/$lv1
|
lvremove --yes $vg/$lv1
|
||||||
done
|
done
|
||||||
@@ -43,8 +46,8 @@ lvcreate --yes --type raid1 --nosync -m 2 -l 1 -n $lv1 $vg
|
|||||||
check raid_leg_status $vg $lv1 "AAA"
|
check raid_leg_status $vg $lv1 "AAA"
|
||||||
lvremove --yes $vg/$lv1
|
lvremove --yes $vg/$lv1
|
||||||
|
|
||||||
for r in raid4 raid5
|
for r in $segtypes
|
||||||
do
|
do
|
||||||
# raid4/5 support resynchronization
|
# raid4/5 support resynchronization
|
||||||
lvcreate --yes --type $r -i 3 -l 2 -n $lv1 $vg
|
lvcreate --yes --type $r -i 3 -l 2 -n $lv1 $vg
|
||||||
check raid_leg_status $vg $lv1 "aaaa"
|
check raid_leg_status $vg $lv1 "aaaa"
|
||||||
|
@@ -23,6 +23,9 @@ lv_devices() {
|
|||||||
########################################################
|
########################################################
|
||||||
aux have_raid 1 3 0 || skip
|
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
|
aux prepare_pvs 6 20 # 6 devices for RAID10 (2-mirror,3-stripe) test
|
||||||
vgcreate -s 512k $vg $(cat DEVICES)
|
vgcreate -s 512k $vg $(cat DEVICES)
|
||||||
|
|
||||||
@@ -54,7 +57,7 @@ aux wait_for_sync $vg $lv1
|
|||||||
lvremove -ff $vg
|
lvremove -ff $vg
|
||||||
|
|
||||||
# Create RAID 4/5/6 (explicit 3-stripe + parity devs)
|
# 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 \
|
raid5 raid5_ls raid5_la raid5_rs raid5_ra \
|
||||||
raid6 raid6_zr raid6_nr raid6_nc; do
|
raid6 raid6_zr raid6_nr raid6_nc; do
|
||||||
|
|
||||||
@@ -64,7 +67,7 @@ for i in raid4 \
|
|||||||
done
|
done
|
||||||
|
|
||||||
# Create RAID 4/5/6 (explicit 3-stripe + parity devs) - Set min/max recovery
|
# 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 \
|
raid5 raid5_ls raid5_la raid5_rs raid5_ra \
|
||||||
raid6 raid6_zr raid6_nr raid6_nc; do
|
raid6 raid6_zr raid6_nr raid6_nc; do
|
||||||
|
|
||||||
|
@@ -24,6 +24,28 @@ pvscan --cache
|
|||||||
|
|
||||||
vgs | grep $vg1
|
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
|
# When MDA is ignored on PV, do not read any VG
|
||||||
# metadata from such PV as it may contain old
|
# metadata from such PV as it may contain old
|
||||||
# metadata which hasn't been updated for some
|
# metadata which hasn't been updated for some
|
||||||
|
@@ -16,6 +16,9 @@ SKIP_WITH_LVMPOLLD=1
|
|||||||
|
|
||||||
aux have_raid 1 3 0 || skip
|
aux have_raid 1 3 0 || skip
|
||||||
|
|
||||||
|
levels="5 6"
|
||||||
|
aux have_raid4 && levels="4 5 6"
|
||||||
|
|
||||||
aux prepare_pvs 6 80
|
aux prepare_pvs 6 80
|
||||||
|
|
||||||
vgcreate -s 256K $vg $(cat DEVICES)
|
vgcreate -s 256K $vg $(cat DEVICES)
|
||||||
@@ -37,7 +40,7 @@ for deactivate in true false; do
|
|||||||
#check raid_images_contiguous $vg $lv1
|
#check raid_images_contiguous $vg $lv1
|
||||||
|
|
||||||
# Extend and reduce 3-striped RAID 4/5/6
|
# 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
|
lvcreate --type raid$i -i 3 -l 3 -n $lv2 $vg
|
||||||
|
|
||||||
test $deactivate && {
|
test $deactivate && {
|
||||||
@@ -59,7 +62,7 @@ done
|
|||||||
|
|
||||||
# Bug 1005434
|
# Bug 1005434
|
||||||
# Ensure extend is contiguous
|
# 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
|
lvextend -l +2 --alloc contiguous $vg/$lv1
|
||||||
check lv_tree_on $vg $lv1 "$dev4" "$dev5" "$dev6"
|
check lv_tree_on $vg $lv1 "$dev4" "$dev5" "$dev6"
|
||||||
|
|
||||||
|
@@ -76,7 +76,7 @@ test_pvmove_resume() {
|
|||||||
aux enable_dev "$dev2"
|
aux enable_dev "$dev2"
|
||||||
|
|
||||||
i=0
|
i=0
|
||||||
while get lv_field $vg name -a | grep "^pvmove"; do
|
while get lv_field $vg name -a | egrep "^\[?pvmove"; do
|
||||||
# wait for 30 secs at max
|
# wait for 30 secs at max
|
||||||
test $i -ge 300 && die "Pvmove is too slow or does not progress."
|
test $i -ge 300 && die "Pvmove is too slow or does not progress."
|
||||||
sleep .1
|
sleep .1
|
||||||
|
@@ -89,7 +89,7 @@ test_pvmove_resume() {
|
|||||||
aux enable_dev "$dev5"
|
aux enable_dev "$dev5"
|
||||||
|
|
||||||
i=0
|
i=0
|
||||||
while get lv_field $vg name -a | grep "^\[?pvmove"; do
|
while get lv_field $vg name -a | egrep "^\[?pvmove"; do
|
||||||
# wait for 30 secs at max
|
# wait for 30 secs at max
|
||||||
test $i -ge 300 && die "Pvmove is too slow or does not progress."
|
test $i -ge 300 && die "Pvmove is too slow or does not progress."
|
||||||
sleep .1
|
sleep .1
|
||||||
|
@@ -40,13 +40,14 @@ snap_and_merge() {
|
|||||||
kill $SLEEP_PID
|
kill $SLEEP_PID
|
||||||
|
|
||||||
aux delay_dev "$dev1" 0 200 $(get first_extent_sector "$dev1"):
|
aux delay_dev "$dev1" 0 200 $(get first_extent_sector "$dev1"):
|
||||||
lvchange --refresh $vg/$lv1
|
lvchange --poll n --refresh $vg/$lv1
|
||||||
dmsetup table
|
dmsetup table
|
||||||
lvs -a -o+lv_merging,lv_merge_failed $vg
|
lvs -a -o+lv_merging,lv_merge_failed $vg
|
||||||
sleep 1
|
sleep 1
|
||||||
check lv_attr_bit state $vg/$lv1 "a"
|
check lv_attr_bit state $vg/$lv1 "a"
|
||||||
check lv_attr_bit state $vg/$lv2 "a"
|
check lv_attr_bit state $vg/$lv2 "a"
|
||||||
aux error_dev "$dev2" $(get first_extent_sector "$dev2"):
|
aux error_dev "$dev2" $(get first_extent_sector "$dev2"):
|
||||||
|
aux enable_dev "$dev1"
|
||||||
# delay to let snapshot merge 'discover' failing COW device
|
# delay to let snapshot merge 'discover' failing COW device
|
||||||
sleep 1
|
sleep 1
|
||||||
sync
|
sync
|
||||||
@@ -56,7 +57,7 @@ snap_and_merge() {
|
|||||||
check lv_attr_bit state $vg/$lv2 "m"
|
check lv_attr_bit state $vg/$lv2 "m"
|
||||||
|
|
||||||
# device OK and running in full speed
|
# device OK and running in full speed
|
||||||
aux enable_dev "$dev1" "$dev2"
|
aux enable_dev "$dev2"
|
||||||
|
|
||||||
# reactivate so merge can finish
|
# reactivate so merge can finish
|
||||||
lvchange -an $vg
|
lvchange -an $vg
|
||||||
|
@@ -88,7 +88,7 @@ lvremove -f $vg/$lv1
|
|||||||
# to make sure preload of origin's metadata is _not_ performed
|
# to make sure preload of origin's metadata is _not_ performed
|
||||||
setup_merge_ $vg $lv1
|
setup_merge_ $vg $lv1
|
||||||
mount "$(lvdev_ $vg $lv1)" test_mnt
|
mount "$(lvdev_ $vg $lv1)" test_mnt
|
||||||
lvconvert --merge $vg/$(snap_lv_name_ $lv1)
|
lvconvert --mergesnapshot $vg/$(snap_lv_name_ $lv1)
|
||||||
# -- refresh LV while FS is still mounted (merge must not start),
|
# -- refresh LV while FS is still mounted (merge must not start),
|
||||||
# verify 'snapshot-origin' target is still being used
|
# verify 'snapshot-origin' target is still being used
|
||||||
lvchange --refresh $vg/$lv1
|
lvchange --refresh $vg/$lv1
|
||||||
@@ -99,7 +99,7 @@ lvremove -f $vg/$lv1
|
|||||||
|
|
||||||
# test multiple snapshot merge; tests copy out that is driven by merge
|
# test multiple snapshot merge; tests copy out that is driven by merge
|
||||||
setup_merge_ $vg $lv1 1
|
setup_merge_ $vg $lv1 1
|
||||||
lvconvert --merge $vg/$(snap_lv_name_ $lv1)
|
lvconvert --mergesnapshot $vg/$(snap_lv_name_ $lv1)
|
||||||
lvremove -f $vg/$lv1
|
lvremove -f $vg/$lv1
|
||||||
|
|
||||||
|
|
||||||
@@ -108,7 +108,7 @@ setup_merge_ $vg $lv1
|
|||||||
setup_merge_ $vg $lv2
|
setup_merge_ $vg $lv2
|
||||||
lvchange --addtag this_is_a_test $vg/$(snap_lv_name_ $lv1)
|
lvchange --addtag this_is_a_test $vg/$(snap_lv_name_ $lv1)
|
||||||
lvchange --addtag this_is_a_test $vg/$(snap_lv_name_ $lv2)
|
lvchange --addtag this_is_a_test $vg/$(snap_lv_name_ $lv2)
|
||||||
lvconvert --merge @this_is_a_test
|
lvconvert --mergesnapshot @this_is_a_test
|
||||||
lvs $vg | tee out
|
lvs $vg | tee out
|
||||||
not grep $(snap_lv_name_ $lv1) out
|
not grep $(snap_lv_name_ $lv1) out
|
||||||
not grep $(snap_lv_name_ $lv2) out
|
not grep $(snap_lv_name_ $lv2) out
|
||||||
|
@@ -17,6 +17,8 @@
|
|||||||
* Put all long args that don't have a corresponding short option first.
|
* Put all long args that don't have a corresponding short option first.
|
||||||
*/
|
*/
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
|
arg(ARG_UNUSED, '-', "", 0, 0, 0) /* place holder for unused 0 value */
|
||||||
|
|
||||||
arg(abort_ARG, '\0', "abort", 0, 0, 0)
|
arg(abort_ARG, '\0', "abort", 0, 0, 0)
|
||||||
arg(activationmode_ARG, '\0', "activationmode", activationmode_VAL, 0, 0)
|
arg(activationmode_ARG, '\0', "activationmode", activationmode_VAL, 0, 0)
|
||||||
arg(addtag_ARG, '\0', "addtag", tag_VAL, ARG_GROUPABLE, 0)
|
arg(addtag_ARG, '\0', "addtag", tag_VAL, ARG_GROUPABLE, 0)
|
||||||
@@ -58,6 +60,7 @@ arg(locktype_ARG, '\0', "locktype", locktype_VAL, 0, 0)
|
|||||||
arg(logonly_ARG, '\0', "logonly", 0, 0, 0)
|
arg(logonly_ARG, '\0', "logonly", 0, 0, 0)
|
||||||
arg(maxrecoveryrate_ARG, '\0', "maxrecoveryrate", sizekb_VAL, 0, 0)
|
arg(maxrecoveryrate_ARG, '\0', "maxrecoveryrate", sizekb_VAL, 0, 0)
|
||||||
arg(merge_ARG, '\0', "merge", 0, 0, 0)
|
arg(merge_ARG, '\0', "merge", 0, 0, 0)
|
||||||
|
arg(mergesnapshot_ARG, '\0', "mergesnapshot", 0, 0, 0)
|
||||||
arg(mergedconfig_ARG, '\0', "mergedconfig", 0, 0, 0)
|
arg(mergedconfig_ARG, '\0', "mergedconfig", 0, 0, 0)
|
||||||
arg(metadatacopies_ARG, '\0', "metadatacopies", metadatacopies_VAL, 0, 0)
|
arg(metadatacopies_ARG, '\0', "metadatacopies", metadatacopies_VAL, 0, 0)
|
||||||
arg(metadataignore_ARG, '\0', "metadataignore", bool_VAL, 0, 0)
|
arg(metadataignore_ARG, '\0', "metadataignore", bool_VAL, 0, 0)
|
||||||
|
@@ -3,8 +3,8 @@
|
|||||||
# and tools/command-lines-count.h must be regenerated
|
# and tools/command-lines-count.h must be regenerated
|
||||||
# with:
|
# with:
|
||||||
#
|
#
|
||||||
# scripts/create-commands --output count scripts/command-lines.in > tools/command-lines-count.h
|
# tools/create-commands --output count tools/command-lines.in > tools/command-lines-count.h
|
||||||
# scripts/create-commands --output struct scripts/command-lines.in > tools/command-lines.h
|
# tools/create-commands --output struct tools/command-lines.in > tools/command-lines.h
|
||||||
#
|
#
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -83,6 +83,13 @@
|
|||||||
# Also, --thinpool VG/LV or --cachepool VG/LV can be used in
|
# Also, --thinpool VG/LV or --cachepool VG/LV can be used in
|
||||||
# place of --name to provide the VG name instead of pos 1.
|
# place of --name to provide the VG name instead of pos 1.
|
||||||
#
|
#
|
||||||
|
# Note that one the most difficult aspect of these definitions is
|
||||||
|
# the variants of --thin / --type thin / --type thin-pool,
|
||||||
|
# --cache / --type cache / --type cache-pool.
|
||||||
|
# There are no consistent rules to follow and the behaviors are
|
||||||
|
# unpredictable; each possible variation and combination needs
|
||||||
|
# to be tested individually to see what it means.
|
||||||
|
#
|
||||||
# Some options have multiple names, but only one form of the name
|
# Some options have multiple names, but only one form of the name
|
||||||
# is used in these definitions. Synonyms will be recognized when
|
# is used in these definitions. Synonyms will be recognized when
|
||||||
# matching a command to a command definition.
|
# matching a command to a command definition.
|
||||||
@@ -115,30 +122,41 @@
|
|||||||
# included in the text as indicators of new lines when printing
|
# included in the text as indicators of new lines when printing
|
||||||
# the descriptions for help/man output.
|
# the descriptions for help/man output.
|
||||||
#
|
#
|
||||||
# Note that one the most difficult aspect of these definitions is
|
# RULE: rules that a given command must follow, i.e. required (and)
|
||||||
# the variants of --thin / --type thin / --type thin-pool,
|
# or invalid (not) combinations of options, LV types or LV properties.
|
||||||
# --cache / --type cache / --type cache-pool.
|
|
||||||
# There are no consistent rules to follow and the behaviors are
|
|
||||||
# unpredictable; each possible variation and combination needs
|
|
||||||
# to be tested individually to see what it means.
|
|
||||||
#
|
#
|
||||||
# Another capability we might want to add here is a way to express
|
# RULE: A and|not B
|
||||||
# rules, per definition, of what arg combinations are allowed or
|
|
||||||
# required, e.g.
|
|
||||||
#
|
#
|
||||||
# if --foo is set, then --bar cannot be set could be encoded as:
|
# Conditions in A are applied to a given command+LV.
|
||||||
# RULE_OPT_INCOMPAT_OPT: --foo --bar
|
# If the conditions in A are true, then the checks in B
|
||||||
|
# are applied. If the checks in B are true|false according
|
||||||
|
# to and|not, then the command fails|continues.
|
||||||
#
|
#
|
||||||
# if --foo is set, then --bar is required could be encoded as:
|
# When A is "all", the conditions in B are always applied.
|
||||||
# RULE_OPT_REQUIRES_OPT: --foo --bar
|
|
||||||
#
|
#
|
||||||
# if --foo is set, then positional arg 1 is required
|
# Conditions:
|
||||||
# RULE_OPT_REQUIRES_POS: --foo 1
|
# . if any --option listed is set, the checks may apply
|
||||||
|
# . if any LV_type listed matches LV, the checks may apply
|
||||||
|
# . if all lv_is_prop listed matches LV, the checks may apply
|
||||||
|
# . if all of the above pass, then perform the checks
|
||||||
#
|
#
|
||||||
# Another thing to add is more details about accpeted LVs.
|
# Checks for "and":
|
||||||
# Checks encoded here can be done in the generic process_each code.
|
# . if any --option listed is not set, then fail
|
||||||
# LV_TYPE: thinpool, mirror (one must be true)
|
# . if none of the LV_types matches the LV, then fail
|
||||||
# LV_PROP: lv_is_pvmove, lv_is_merging (all must be true)
|
# . if any of the lv_is_prop do not match the LV, then fail
|
||||||
|
#
|
||||||
|
# Checks for "not":
|
||||||
|
# . if any --option listed is set, then fail
|
||||||
|
# . if any of the LV_types matches the LV, then fail
|
||||||
|
# . if any of the lv_is_prop match the LV, then fail
|
||||||
|
#
|
||||||
|
# RULE: --option|LV_type|lv_is_prop|all ... and|not --option|LV_type|lv_is_prop ...
|
||||||
|
#
|
||||||
|
# RULE: --opt1 not --opt2
|
||||||
|
# RULE: --opt1 and --opt2
|
||||||
|
# RULE: --opt1 LV_type1 lv_is_prop1 and --opt2
|
||||||
|
# RULE: --opt1 LV_type1 and lv_is_prop1
|
||||||
|
# RULE: LV_type1 and lv_is_prop1
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
@@ -204,9 +222,9 @@ OO_CONFIG: --atversion String, --typeconfig ConfigType, --file String, --ignorea
|
|||||||
|
|
||||||
# None of these can function as a required option for lvchange.
|
# None of these can function as a required option for lvchange.
|
||||||
|
|
||||||
OO_LVCHANGE: --autobackup Bool, --force, --ignorelockingfailure,
|
OO_LVCHANGE: --autobackup Bool, --force, --ignoremonitoring,
|
||||||
--ignoremonitoring, --ignoreskippedcluster, --noudevsync,
|
--ignoreskippedcluster, --noudevsync, --reportformat ReportFmt,
|
||||||
--reportformat ReportFmt, --sysinit, --select String
|
--select String
|
||||||
|
|
||||||
# Any of these can function as a required option for lvchange.
|
# Any of these can function as a required option for lvchange.
|
||||||
# profile is also part of OO_ALL, but is repeated in OO_LVCHANGE_META
|
# profile is also part of OO_ALL, but is repeated in OO_LVCHANGE_META
|
||||||
@@ -219,30 +237,48 @@ OO_LVCHANGE_META: --addtag Tag, --deltag Tag,
|
|||||||
--errorwhenfull Bool, --discards Discards, --zero Bool,
|
--errorwhenfull Bool, --discards Discards, --zero Bool,
|
||||||
--cachemode CacheMode, --cachepolicy String, --cachesettings String,
|
--cachemode CacheMode, --cachepolicy String, --cachesettings String,
|
||||||
--minrecoveryrate SizeKB, --maxrecoveryrate SizeKB,
|
--minrecoveryrate SizeKB, --maxrecoveryrate SizeKB,
|
||||||
--writebehind Number, --writemostly WriteMostlyPV
|
--writebehind Number, --writemostly WriteMostlyPV, --persistent n
|
||||||
|
|
||||||
lvchange OO_LVCHANGE_META VG|LV|Tag|Select ...
|
lvchange OO_LVCHANGE_META VG|LV|Tag|Select ...
|
||||||
OO: OO_LVCHANGE
|
OO: OO_LVCHANGE
|
||||||
ID: lvchange_properties
|
ID: lvchange_properties
|
||||||
DESC: Change a general LV property.
|
DESC: Change a general LV property.
|
||||||
|
RULE: all not lv_is_pvmove lv_is_mirror_log lv_is_mirror_image
|
||||||
|
RULE: all and lv_is_vg_writable
|
||||||
|
RULE: --contiguous not --alloc
|
||||||
|
RULE: --profile not --detachprofile
|
||||||
|
RULE: --metadataprofile not --detachprofile
|
||||||
|
RULE: --minrecoveryrate --maxrecoveryrate and LV_raid
|
||||||
|
RULE: --writebehind --writemostly and LV_raid1
|
||||||
|
RULE: --cachemode --cachepolicy --cachesettings and LV_cache LV_cachepool
|
||||||
|
RULE: --errorwhenfull --discards --zero and LV_thinpool
|
||||||
|
RULE: --permission not lv_is_external_origin lv_is_raid_metadata lv_is_raid_image LV_thinpool
|
||||||
|
RULE: --alloc --contiguous --metadataprofile --permission --persistent --profile --readahead not lv_is_thick_origin
|
||||||
|
RULE: --alloc --discards --zero --cachemode --cachepolicy --cachesettings not lv_is_partial
|
||||||
|
|
||||||
lvchange --resync VG|LV_raid_mirror|Tag|Select ...
|
lvchange --resync VG|LV_raid_mirror|Tag|Select ...
|
||||||
OO: OO_LVCHANGE
|
OO: OO_LVCHANGE
|
||||||
ID: lvchange_resync
|
ID: lvchange_resync
|
||||||
DESC: Resyncronize a mirror or raid LV.
|
DESC: Resyncronize a mirror or raid LV.
|
||||||
|
RULE: all not lv_is_pvmove lv_is_locked
|
||||||
|
RULE: all not LV_raid0
|
||||||
|
|
||||||
lvchange --syncaction SyncAction VG|LV_raid|Tag|Select ...
|
lvchange --syncaction SyncAction VG|LV_raid|Tag|Select ...
|
||||||
OO: OO_LVCHANGE
|
OO: OO_LVCHANGE
|
||||||
ID: lvchange_syncaction
|
ID: lvchange_syncaction
|
||||||
DESC: Resynchronize or check a raid LV.
|
DESC: Resynchronize or check a raid LV.
|
||||||
|
RULE: all not LV_raid0
|
||||||
|
|
||||||
lvchange --rebuild PV VG|LV_raid|Tag|Select ...
|
lvchange --rebuild PV VG|LV_raid|Tag|Select ...
|
||||||
OO: OO_LVCHANGE
|
OO: OO_LVCHANGE
|
||||||
ID: lvchange_rebuild
|
ID: lvchange_rebuild
|
||||||
DESC: Reconstruct data on specific PVs of a raid LV.
|
DESC: Reconstruct data on specific PVs of a raid LV.
|
||||||
|
RULE: all not LV_raid0
|
||||||
|
|
||||||
|
# try removing the META change options from here?
|
||||||
lvchange --activate Active VG|LV|Tag|Select ...
|
lvchange --activate Active VG|LV|Tag|Select ...
|
||||||
OO: --activationmode ActivationMode, --partial, --ignoreactivationskip, OO_LVCHANGE_META, OO_LVCHANGE
|
OO: --activationmode ActivationMode, --partial, --ignoreactivationskip,
|
||||||
|
--ignorelockingfailure, --sysinit, OO_LVCHANGE_META, OO_LVCHANGE
|
||||||
ID: lvchange_activate
|
ID: lvchange_activate
|
||||||
DESC: Activate or deactivate an LV.
|
DESC: Activate or deactivate an LV.
|
||||||
|
|
||||||
@@ -255,16 +291,18 @@ lvchange --monitor Bool VG|LV|Tag|Select ...
|
|||||||
OO: --poll Bool, OO_LVCHANGE
|
OO: --poll Bool, OO_LVCHANGE
|
||||||
ID: lvchange_monitor
|
ID: lvchange_monitor
|
||||||
DESC: Start or stop monitoring an LV from dmeventd.
|
DESC: Start or stop monitoring an LV from dmeventd.
|
||||||
|
RULE: all not lv_is_pvmove
|
||||||
|
|
||||||
lvchange --poll Bool VG|LV|Tag|Select ...
|
lvchange --poll Bool VG|LV|Tag|Select ...
|
||||||
OO: --monitor Bool, OO_LVCHANGE
|
OO: --monitor Bool, OO_LVCHANGE
|
||||||
ID: lvchange_poll
|
ID: lvchange_poll
|
||||||
DESC: Start or stop processing an LV conversion.
|
DESC: Start or stop processing an LV conversion.
|
||||||
|
|
||||||
lvchange --persistent Bool VG|LV|Tag|Select ...
|
lvchange --persistent y --minor Number LV
|
||||||
OO: --minor Number, --major Number, OO_LVCHANGE
|
OO: --major Number, OO_LVCHANGE
|
||||||
ID: lvchange_persistent
|
ID: lvchange_persistent
|
||||||
DESC: Make the minor device number persistent for an LV.
|
DESC: Make the minor device number persistent for an LV.
|
||||||
|
RULE: all not LV_thinpool LV_cachepool
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -274,8 +312,7 @@ OO_LVCONVERT_RAID: --mirrors SNumber, --stripes_long Number,
|
|||||||
OO_LVCONVERT_POOL: --poolmetadata LV, --poolmetadatasize SizeMB,
|
OO_LVCONVERT_POOL: --poolmetadata LV, --poolmetadatasize SizeMB,
|
||||||
--poolmetadataspare Bool, --readahead Readahead, --chunksize SizeKB
|
--poolmetadataspare Bool, --readahead Readahead, --chunksize SizeKB
|
||||||
|
|
||||||
OO_LVCONVERT: --alloc Alloc, --background, --force, --noudevsync,
|
OO_LVCONVERT: --alloc Alloc, --background, --force, --noudevsync
|
||||||
--usepolicies
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -287,6 +324,7 @@ OO: OO_LVCONVERT_RAID, OO_LVCONVERT
|
|||||||
OP: PV ...
|
OP: PV ...
|
||||||
ID: lvconvert_raid_types
|
ID: lvconvert_raid_types
|
||||||
DESC: Convert LV to linear.
|
DESC: Convert LV to linear.
|
||||||
|
RULE: all not lv_is_locked lv_is_pvmove
|
||||||
|
|
||||||
lvconvert --type striped LV
|
lvconvert --type striped LV
|
||||||
OO: OO_LVCONVERT_RAID, OO_LVCONVERT
|
OO: OO_LVCONVERT_RAID, OO_LVCONVERT
|
||||||
@@ -307,7 +345,7 @@ ID: lvconvert_raid_types
|
|||||||
DESC: Convert LV to raid.
|
DESC: Convert LV to raid.
|
||||||
|
|
||||||
lvconvert --mirrors SNumber LV
|
lvconvert --mirrors SNumber LV
|
||||||
OO: OO_LVCONVERT_RAID, OO_LVCONVERT
|
OO: OO_LVCONVERT_RAID, OO_LVCONVERT, --mirrorlog MirrorLog
|
||||||
OP: PV ...
|
OP: PV ...
|
||||||
ID: lvconvert_raid_types
|
ID: lvconvert_raid_types
|
||||||
DESC: Convert LV to raid1 or mirror, or change number of mirror images.
|
DESC: Convert LV to raid1 or mirror, or change number of mirror images.
|
||||||
@@ -374,6 +412,7 @@ FLAGS: SECONDARY_SYNTAX
|
|||||||
lvconvert --type thin-pool LV_linear_striped_raid_cache
|
lvconvert --type thin-pool LV_linear_striped_raid_cache
|
||||||
OO: --stripes_long Number, --stripesize SizeKB,
|
OO: --stripes_long Number, --stripesize SizeKB,
|
||||||
--discards Discards, --zero Bool, OO_LVCONVERT_POOL, OO_LVCONVERT
|
--discards Discards, --zero Bool, OO_LVCONVERT_POOL, OO_LVCONVERT
|
||||||
|
OP: PV ...
|
||||||
ID: lvconvert_to_thinpool
|
ID: lvconvert_to_thinpool
|
||||||
DESC: Convert LV to type thin-pool.
|
DESC: Convert LV to type thin-pool.
|
||||||
|
|
||||||
@@ -382,6 +421,7 @@ DESC: Convert LV to type thin-pool.
|
|||||||
lvconvert --thinpool LV_linear_striped_raid_cache
|
lvconvert --thinpool LV_linear_striped_raid_cache
|
||||||
OO: --type thin-pool, --stripes_long Number, --stripesize SizeKB,
|
OO: --type thin-pool, --stripes_long Number, --stripesize SizeKB,
|
||||||
--discards Discards, --zero Bool, OO_LVCONVERT_POOL, OO_LVCONVERT
|
--discards Discards, --zero Bool, OO_LVCONVERT_POOL, OO_LVCONVERT
|
||||||
|
OP: PV ...
|
||||||
ID: lvconvert_to_thinpool
|
ID: lvconvert_to_thinpool
|
||||||
DESC: Convert LV to type thin-pool (variant, use --type thin-pool).
|
DESC: Convert LV to type thin-pool (variant, use --type thin-pool).
|
||||||
FLAGS: SECONDARY_SYNTAX
|
FLAGS: SECONDARY_SYNTAX
|
||||||
@@ -391,6 +431,7 @@ FLAGS: SECONDARY_SYNTAX
|
|||||||
lvconvert --type cache-pool LV_linear_striped_raid
|
lvconvert --type cache-pool LV_linear_striped_raid
|
||||||
OO: OO_LVCONVERT_POOL, OO_LVCONVERT,
|
OO: OO_LVCONVERT_POOL, OO_LVCONVERT,
|
||||||
--cachemode CacheMode, --cachepolicy String, --cachesettings String
|
--cachemode CacheMode, --cachepolicy String, --cachesettings String
|
||||||
|
OP: PV ...
|
||||||
ID: lvconvert_to_cachepool
|
ID: lvconvert_to_cachepool
|
||||||
DESC: Convert LV to type cache-pool.
|
DESC: Convert LV to type cache-pool.
|
||||||
|
|
||||||
@@ -462,13 +503,19 @@ ID: lvconvert_merge
|
|||||||
DESC: Merge LV that was previously split from a mirror.
|
DESC: Merge LV that was previously split from a mirror.
|
||||||
DESC: Merge thin LV into its origin LV.
|
DESC: Merge thin LV into its origin LV.
|
||||||
DESC: Merge COW snapshot LV into its origin.
|
DESC: Merge COW snapshot LV into its origin.
|
||||||
|
RULE: all not lv_is_merging_origin lv_is_virtual_origin lv_is_external_origin lv_is_merging_cow
|
||||||
|
|
||||||
|
lvconvert --mergesnapshot LV_snapshot ...
|
||||||
|
OO: --background, --interval Number, OO_LVCONVERT
|
||||||
|
ID: lvconvert_merge_snapshot
|
||||||
|
DESC: Merge LV that was previously split from a mirror.
|
||||||
|
RULE: all not lv_is_merging_origin lv_is_virtual_origin lv_is_external_origin lv_is_merging_cow
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# FIXME: by using two different positional args, this is the
|
# NB: an unsual use of position args here, where
|
||||||
# single violation of the standard method of using process_each_lv().
|
# the second position LV is the only one processed
|
||||||
# Before calling process_each, it steals the first positional arg
|
# by process_each_lv.
|
||||||
# and adjusts argv/argc so it's not seen by process_each.
|
|
||||||
|
|
||||||
# alternate form of lvconvert --snapshot
|
# alternate form of lvconvert --snapshot
|
||||||
lvconvert --type snapshot LV_linear_striped_raid LV_snapshot
|
lvconvert --type snapshot LV_linear_striped_raid LV_snapshot
|
||||||
@@ -499,7 +546,8 @@ DESC: Combine LV with a previously split snapshot LV.
|
|||||||
# and the LV type is known.
|
# and the LV type is known.
|
||||||
|
|
||||||
lvconvert --repair LV_raid_mirror_thinpool
|
lvconvert --repair LV_raid_mirror_thinpool
|
||||||
OO: OO_LVCONVERT
|
OO: --usepolicies, --interval Number, OO_LVCONVERT
|
||||||
|
OP: PV ...
|
||||||
ID: lvconvert_repair_pvs_or_thinpool
|
ID: lvconvert_repair_pvs_or_thinpool
|
||||||
DESC: Replace failed PVs in a raid or mirror LV.
|
DESC: Replace failed PVs in a raid or mirror LV.
|
||||||
DESC: Repair a thin pool.
|
DESC: Repair a thin pool.
|
||||||
@@ -518,6 +566,7 @@ lvconvert --splitsnapshot LV_snapshot
|
|||||||
OO: OO_LVCONVERT
|
OO: OO_LVCONVERT
|
||||||
ID: lvconvert_split_cow_snapshot
|
ID: lvconvert_split_cow_snapshot
|
||||||
DESC: Separate a COW snapshot from its origin LV.
|
DESC: Separate a COW snapshot from its origin LV.
|
||||||
|
RULE: all not lv_is_origin lv_is_external_origin lv_is_merging_cow lv_is_vg_writable lv_is_pvmove
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -1003,6 +1052,7 @@ lvextend --usepolicies LV_thinpool_snapshot
|
|||||||
OO: --alloc Alloc, --autobackup Bool, --force, --mirrors SNumber,
|
OO: --alloc Alloc, --autobackup Bool, --force, --mirrors SNumber,
|
||||||
--nofsck, --nosync, --noudevsync,
|
--nofsck, --nosync, --noudevsync,
|
||||||
--reportformat ReportFmt, --resizefs
|
--reportformat ReportFmt, --resizefs
|
||||||
|
OP: PV ...
|
||||||
ID: lvextend_by_policy
|
ID: lvextend_by_policy
|
||||||
DESC: Extend an LV according to a predefined policy.
|
DESC: Extend an LV according to a predefined policy.
|
||||||
|
|
||||||
@@ -1010,6 +1060,7 @@ DESC: Extend an LV according to a predefined policy.
|
|||||||
|
|
||||||
lvmconfig
|
lvmconfig
|
||||||
OO: OO_CONFIG
|
OO: OO_CONFIG
|
||||||
|
OP: String ...
|
||||||
ID: lvmconfig_general
|
ID: lvmconfig_general
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -1073,9 +1124,15 @@ ID: lvs_general
|
|||||||
|
|
||||||
lvscan
|
lvscan
|
||||||
OO: --all, --blockdevice, --ignorelockingfailure, --partial,
|
OO: --all, --blockdevice, --ignorelockingfailure, --partial,
|
||||||
--readonly, --reportformat ReportFmt, --cache_long
|
--readonly, --reportformat ReportFmt
|
||||||
ID: lvscan_general
|
ID: lvscan_general
|
||||||
|
|
||||||
|
lvscan --cache_long
|
||||||
|
OO: --blockdevice, --ignorelockingfailure, --partial,
|
||||||
|
--readonly, --reportformat ReportFmt
|
||||||
|
OP: LV ...
|
||||||
|
ID: lvscan_cache
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# None of these can function as a required option for pvchange.
|
# None of these can function as a required option for pvchange.
|
||||||
@@ -1142,7 +1199,7 @@ ID: pvmove_one
|
|||||||
DESC: Move PV extents.
|
DESC: Move PV extents.
|
||||||
|
|
||||||
pvmove
|
pvmove
|
||||||
OO: --abort, --background
|
OO: --abort, --background, --interval Number
|
||||||
ID: pvmove_any
|
ID: pvmove_any
|
||||||
DESC: Continue or abort existing pvmove operations.
|
DESC: Continue or abort existing pvmove operations.
|
||||||
|
|
||||||
@@ -1169,7 +1226,7 @@ DESC: Display PV information.
|
|||||||
|
|
||||||
pvscan --cache_long
|
pvscan --cache_long
|
||||||
OO: --ignorelockingfailure, --reportformat ReportFmt, --background,
|
OO: --ignorelockingfailure, --reportformat ReportFmt, --background,
|
||||||
--activate Active, --major Number, --minor Number,
|
--activate Active, --major Number, --minor Number
|
||||||
OP: PV|String ...
|
OP: PV|String ...
|
||||||
ID: pvscan_cache
|
ID: pvscan_cache
|
||||||
DESC: Populate the lvmetad cache by scanning PVs.
|
DESC: Populate the lvmetad cache by scanning PVs.
|
||||||
@@ -1184,12 +1241,32 @@ ID: vgcfgbackup_general
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
OO_VGCFGRESTORE: --force_long, --metadatatype MetadataType
|
||||||
|
|
||||||
vgcfgrestore VG
|
vgcfgrestore VG
|
||||||
OO: --file String, --force_long, --list, --metadatatype MetadataType
|
OO: OO_VGCFGRESTORE
|
||||||
ID: vgcfgrestore_by_vg
|
ID: vgcfgrestore_by_vg
|
||||||
|
DESC: Restore VG metadata from last backup.
|
||||||
|
|
||||||
|
vgcfgrestore --file String VG
|
||||||
|
OO: OO_VGCFGRESTORE
|
||||||
|
ID: vgcfgrestore_by_file
|
||||||
|
DESC: Restore VG metadata from specified file.
|
||||||
|
|
||||||
|
vgcfgrestore --list VG
|
||||||
|
OO: OO_VGCFGRESTORE
|
||||||
|
ID: vgcfgrestore_list_by_vg
|
||||||
|
DESC: List all VG metadata backups.
|
||||||
|
|
||||||
|
# FIXME: the optional VG pos arg is not used or checked and can be
|
||||||
|
# anything, but a test in the test suite uses it. Fix the test or
|
||||||
|
# verify that the positional VG is correct?
|
||||||
|
|
||||||
vgcfgrestore --list --file String
|
vgcfgrestore --list --file String
|
||||||
ID: vgcfgrestore_by_file
|
OO: OO_VGCFGRESTORE
|
||||||
|
OP: VG
|
||||||
|
ID: vgcfgrestore_list_by_file
|
||||||
|
DESC: List one VG metadata backup file.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -1206,7 +1283,7 @@ OO_VGCHANGE_META: --addtag Tag, --deltag Tag,
|
|||||||
--logicalvolume Number, --maxphysicalvolumes Number, --alloc Alloc, --uuid,
|
--logicalvolume Number, --maxphysicalvolumes Number, --alloc Alloc, --uuid,
|
||||||
--clustered Bool, --pvmetadatacopies MetadataCopiesPV, --vgmetadatacopies MetadataCopiesVG,
|
--clustered Bool, --pvmetadatacopies MetadataCopiesPV, --vgmetadatacopies MetadataCopiesVG,
|
||||||
--physicalextentsize SizeMB, --resizeable Bool, --systemid String, --locktype LockType,
|
--physicalextentsize SizeMB, --resizeable Bool, --systemid String, --locktype LockType,
|
||||||
--profile String, --detachprofile, --metadataprofile String,
|
--profile String, --detachprofile, --metadataprofile String
|
||||||
|
|
||||||
vgchange OO_VGCHANGE_META
|
vgchange OO_VGCHANGE_META
|
||||||
OO: OO_VGCHANGE
|
OO: OO_VGCHANGE
|
||||||
@@ -1420,15 +1497,19 @@ DESC: Split a VG by PVs in a specified LV.
|
|||||||
|
|
||||||
# built-in and deprecated commands
|
# built-in and deprecated commands
|
||||||
|
|
||||||
|
# use lvmconfig
|
||||||
config
|
config
|
||||||
OO: OO_CONFIG
|
OO: OO_CONFIG
|
||||||
OP: String ...
|
OP: String ...
|
||||||
ID: lvmconfig_general
|
ID: lvmconfig_general
|
||||||
|
FLAGS: SECONDARY_SYNTAX
|
||||||
|
|
||||||
|
# use lvmconfig
|
||||||
dumpconfig
|
dumpconfig
|
||||||
OO: OO_CONFIG
|
OO: OO_CONFIG
|
||||||
OP: String ...
|
OP: String ...
|
||||||
ID: lvmconfig_general
|
ID: lvmconfig_general
|
||||||
|
FLAGS: SECONDARY_SYNTAX
|
||||||
|
|
||||||
devtypes
|
devtypes
|
||||||
OO: --aligned, --binary, --nameprefixes, --noheadings,
|
OO: --aligned, --binary, --nameprefixes, --noheadings,
|
||||||
@@ -1458,8 +1539,10 @@ ID: help_general
|
|||||||
version
|
version
|
||||||
ID: version_general
|
ID: version_general
|
||||||
|
|
||||||
|
# deprecated
|
||||||
pvdata
|
pvdata
|
||||||
ID: pvdata_general
|
ID: pvdata_general
|
||||||
|
FLAGS: SECONDARY_SYNTAX
|
||||||
|
|
||||||
segtypes
|
segtypes
|
||||||
ID: segtypes_general
|
ID: segtypes_general
|
||||||
@@ -1470,17 +1553,25 @@ ID: systemid_general
|
|||||||
tags
|
tags
|
||||||
ID: tags_general
|
ID: tags_general
|
||||||
|
|
||||||
|
# deprecated
|
||||||
lvmchange
|
lvmchange
|
||||||
ID: lvmchange_general
|
ID: lvmchange_general
|
||||||
|
FLAGS: SECONDARY_SYNTAX
|
||||||
|
|
||||||
|
# deprecated
|
||||||
lvmdiskscan
|
lvmdiskscan
|
||||||
OO: --lvmpartition, --readonly
|
OO: --lvmpartition, --readonly
|
||||||
ID: lvmdiskscan_general
|
ID: lvmdiskscan_general
|
||||||
|
FLAGS: SECONDARY_SYNTAX
|
||||||
|
|
||||||
|
# deprecated
|
||||||
lvmsadc
|
lvmsadc
|
||||||
ID: lvmsadc_general
|
ID: lvmsadc_general
|
||||||
|
FLAGS: SECONDARY_SYNTAX
|
||||||
|
|
||||||
|
# deprecated
|
||||||
lvmsar
|
lvmsar
|
||||||
OO: --full, --stdin
|
OO: --full, --stdin
|
||||||
ID: lvmsar_general
|
ID: lvmsar_general
|
||||||
|
FLAGS: SECONDARY_SYNTAX
|
||||||
|
|
||||||
|
@@ -54,27 +54,6 @@ struct command_name {
|
|||||||
#define ARG_DEF_FLAG_NEW 1 << 0
|
#define ARG_DEF_FLAG_NEW 1 << 0
|
||||||
#define ARG_DEF_FLAG_MAY_REPEAT 1 << 1
|
#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)
|
static inline int val_bit_is_set(uint64_t val_bits, int val_enum)
|
||||||
{
|
{
|
||||||
return (val_bits & (1 << val_enum)) ? 1 : 0;
|
return (val_bits & (1 << val_enum)) ? 1 : 0;
|
||||||
@@ -85,13 +64,33 @@ static inline uint64_t val_enum_to_bit(int val_enum)
|
|||||||
return (1ULL << val_enum);
|
return (1ULL << val_enum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int lvp_bit_is_set(uint64_t lvp_bits, int lvp_enum)
|
||||||
|
{
|
||||||
|
return (lvp_bits & (1 << lvp_enum)) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t lvp_enum_to_bit(int lvp_enum)
|
||||||
|
{
|
||||||
|
return (1ULL << lvp_enum);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lvt_bit_is_set(uint64_t lvt_bits, int lvt_enum)
|
||||||
|
{
|
||||||
|
return (lvt_bits & (1 << lvt_enum)) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t lvt_enum_to_bit(int lvt_enum)
|
||||||
|
{
|
||||||
|
return (1ULL << lvt_enum);
|
||||||
|
}
|
||||||
|
|
||||||
/* Description a value that follows an option or exists in a position. */
|
/* Description a value that follows an option or exists in a position. */
|
||||||
|
|
||||||
struct arg_def {
|
struct arg_def {
|
||||||
uint64_t val_bits; /* bits of x_VAL, can be multiple for pos_arg */
|
uint64_t val_bits; /* bits of x_VAL, can be multiple for pos_arg */
|
||||||
|
uint64_t lvt_bits; /* lvt_enum_to_bit(x_LVT) for lv_VAL, can be multiple */
|
||||||
uint64_t num; /* a literal number for conststr_VAL */
|
uint64_t num; /* a literal number for conststr_VAL */
|
||||||
const char *str; /* a literal string for constnum_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_ */
|
uint32_t flags; /* ARG_DEF_FLAG_ */
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -109,6 +108,33 @@ struct pos_arg {
|
|||||||
struct arg_def def; /* defines accepted values */
|
struct arg_def def; /* defines accepted values */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Commands using a given command definition must follow a set
|
||||||
|
* of rules. If a given command+LV matches the conditions in
|
||||||
|
* opts/lvt_bits/lvp_bits, then the checks are applied.
|
||||||
|
* If one condition is not met, the checks are not applied.
|
||||||
|
* If no conditions are set, the checks are always applied.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define RULE_INVALID 1
|
||||||
|
#define RULE_REQUIRE 2
|
||||||
|
|
||||||
|
struct cmd_rule {
|
||||||
|
int *opts; /* if any option in this list is set, the check may apply */
|
||||||
|
uint64_t lvt_bits; /* if LV has one of these types (lvt_enum_to_bit), the check may apply */
|
||||||
|
uint64_t lvp_bits; /* if LV has all of these properties (lvp_enum_to_bit), the check may apply */
|
||||||
|
|
||||||
|
int *check_opts; /* used options must [not] be in this list */
|
||||||
|
uint64_t check_lvt_bits; /* LV must [not] have one of these type */
|
||||||
|
uint64_t check_lvp_bits; /* LV must [not] have all of these properties */
|
||||||
|
|
||||||
|
uint32_t rule; /* RULE_INVALID, RULE_REQUIRE: check values must [not] be true */
|
||||||
|
int opts_count; /* entries in opts[] */
|
||||||
|
int check_opts_count; /* entries in check_opts[] */
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CMD_RO_ARGS needs to accomodate a list of options,
|
* CMD_RO_ARGS needs to accomodate a list of options,
|
||||||
* of which one is required after which the rest are
|
* of which one is required after which the rest are
|
||||||
@@ -118,6 +144,7 @@ struct pos_arg {
|
|||||||
#define CMD_OO_ARGS 150 /* optional opt args */
|
#define CMD_OO_ARGS 150 /* optional opt args */
|
||||||
#define CMD_RP_ARGS 8 /* required positional args */
|
#define CMD_RP_ARGS 8 /* required positional args */
|
||||||
#define CMD_OP_ARGS 8 /* optional positional args */
|
#define CMD_OP_ARGS 8 /* optional positional args */
|
||||||
|
#define CMD_MAX_RULES 32 /* max number of rules per command def */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* one or more from required_opt_args is required,
|
* one or more from required_opt_args is required,
|
||||||
@@ -158,6 +185,8 @@ struct command {
|
|||||||
/* optional positional args */
|
/* optional positional args */
|
||||||
struct pos_arg optional_pos_args[CMD_OP_ARGS];
|
struct pos_arg optional_pos_args[CMD_OP_ARGS];
|
||||||
|
|
||||||
|
struct cmd_rule rules[CMD_MAX_RULES];
|
||||||
|
|
||||||
int ro_count;
|
int ro_count;
|
||||||
int oo_count;
|
int oo_count;
|
||||||
int rp_count;
|
int rp_count;
|
||||||
@@ -165,6 +194,8 @@ struct command {
|
|||||||
|
|
||||||
/* used for processing current position */
|
/* used for processing current position */
|
||||||
int pos_count;
|
int pos_count;
|
||||||
|
|
||||||
|
int rule_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -1611,7 +1611,7 @@ static int _udevcomplete_all(CMD_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!_switches[YES_ARG]) {
|
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 ").",
|
"that have a prefix %" PRIu16 " (0x%" PRIx16 ").",
|
||||||
age ? "older than " : "", age, age ? " minutes " : "",
|
age ? "older than " : "", age, age ? " minutes " : "",
|
||||||
DM_COOKIE_MAGIC, DM_COOKIE_MAGIC);
|
DM_COOKIE_MAGIC, DM_COOKIE_MAGIC);
|
||||||
@@ -2707,6 +2707,9 @@ static int _add_dep(CMD_ARGS)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Create and walk dependency tree
|
* 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)
|
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)
|
static int _display_tree(CMD_ARGS)
|
||||||
{
|
{
|
||||||
if (!_build_whole_deptree(cmd))
|
int r;
|
||||||
return_0;
|
|
||||||
|
|
||||||
_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)))
|
selection, NULL, NULL)))
|
||||||
goto_out;
|
goto_out;
|
||||||
|
|
||||||
if ((_report_type & DR_TREE) && cmd && !_build_whole_deptree(cmd)) {
|
r = 1;
|
||||||
err("Internal device dependency tree creation failed.");
|
|
||||||
goto out;
|
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])
|
if (!_switches[INTERVAL_ARG])
|
||||||
@@ -4484,8 +4494,6 @@ static int _report_init(const struct command *cmd, const char *subcommand)
|
|||||||
if (field_prefixes)
|
if (field_prefixes)
|
||||||
dm_report_set_output_field_name_prefix(_report, "dm_");
|
dm_report_set_output_field_name_prefix(_report, "dm_");
|
||||||
|
|
||||||
r = 1;
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (len)
|
if (len)
|
||||||
dm_free(options);
|
dm_free(options);
|
||||||
@@ -5270,6 +5278,8 @@ static int _stats_delete(CMD_ARGS)
|
|||||||
name = argv[0];
|
name = argv[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_switches[PROGRAM_ID_ARG])
|
||||||
|
program_id = _string_args[PROGRAM_ID_ARG];
|
||||||
if (_switches[ALL_PROGRAMS_ARG])
|
if (_switches[ALL_PROGRAMS_ARG])
|
||||||
program_id = DM_STATS_ALL_PROGRAMS;
|
program_id = DM_STATS_ALL_PROGRAMS;
|
||||||
|
|
||||||
@@ -5313,7 +5323,7 @@ static int _stats_delete(CMD_ARGS)
|
|||||||
log_error("Could not delete statistics region");
|
log_error("Could not delete statistics region");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
log_info("Deleted statistics region " FMTu64 ".\n", region_id);
|
log_info("Deleted statistics region " FMTu64 ".", region_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
r = 1;
|
r = 1;
|
||||||
@@ -6782,8 +6792,15 @@ unknown:
|
|||||||
argc--, argv++;
|
argc--, argv++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_switches[COLS_ARG] && !_report_init(cmd, subcommand))
|
/* Default to success */
|
||||||
goto_out;
|
ret = 0;
|
||||||
|
|
||||||
|
if (_switches[COLS_ARG]) {
|
||||||
|
if (!_report_init(cmd, subcommand))
|
||||||
|
ret = 1;
|
||||||
|
if (ret || !_report)
|
||||||
|
goto_out;
|
||||||
|
}
|
||||||
|
|
||||||
if (_switches[COUNT_ARG])
|
if (_switches[COUNT_ARG])
|
||||||
_count = ((uint32_t)_int_args[COUNT_ARG]) ? : UINT32_MAX;
|
_count = ((uint32_t)_int_args[COUNT_ARG]) ? : UINT32_MAX;
|
||||||
@@ -6795,14 +6812,17 @@ unknown:
|
|||||||
&_disp_units);
|
&_disp_units);
|
||||||
if (!_disp_factor) {
|
if (!_disp_factor) {
|
||||||
log_error("Invalid --units argument.");
|
log_error("Invalid --units argument.");
|
||||||
|
ret = 1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Start interval timer. */
|
/* Start interval timer. */
|
||||||
if (_count > 1)
|
if (_count > 1)
|
||||||
if (!_start_timer())
|
if (!_start_timer()) {
|
||||||
|
ret = 1;
|
||||||
goto_out;
|
goto_out;
|
||||||
|
}
|
||||||
|
|
||||||
doit:
|
doit:
|
||||||
multiple_devices = (cmd->repeatable_cmd && argc != 1 &&
|
multiple_devices = (cmd->repeatable_cmd && argc != 1 &&
|
||||||
@@ -6819,18 +6839,19 @@ doit:
|
|||||||
if (_count > 1 && r) {
|
if (_count > 1 && r) {
|
||||||
printf("\n");
|
printf("\n");
|
||||||
/* wait for --interval and update timestamps */
|
/* wait for --interval and update timestamps */
|
||||||
if (!_do_report_wait())
|
if (!_do_report_wait()) {
|
||||||
|
ret = 1;
|
||||||
goto_out;
|
goto_out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!r)
|
if (!r) {
|
||||||
|
ret = 1;
|
||||||
goto_out;
|
goto_out;
|
||||||
|
}
|
||||||
} while (--_count);
|
} while (--_count);
|
||||||
|
|
||||||
/* Success */
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (_report)
|
if (_report)
|
||||||
dm_report_free(_report);
|
dm_report_free(_report);
|
||||||
@@ -6843,5 +6864,5 @@ out:
|
|||||||
if (_initial_timestamp)
|
if (_initial_timestamp)
|
||||||
dm_timestamp_destroy(_initial_timestamp);
|
dm_timestamp_destroy(_initial_timestamp);
|
||||||
|
|
||||||
return ret;
|
return (_switches[HELP_ARG] || _switches[VERSION_ARG]) ? 0 : ret;
|
||||||
}
|
}
|
||||||
|
56
tools/lv_props.h
Normal file
56
tools/lv_props.h
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
* NULL in the last arg can be replaced with actual
|
||||||
|
* calls to the lv_is_prop() function when those
|
||||||
|
* become functions (are #define now), take uniform
|
||||||
|
* args (e.g. some take cmd others don't), and are
|
||||||
|
* exposed in tools.h
|
||||||
|
*
|
||||||
|
* Until then, the lv_is_prop() functions are
|
||||||
|
* called indirectly through _lv_is_prop().
|
||||||
|
*/
|
||||||
|
|
||||||
|
lvp(LVP_NONE, "", NULL) /* enum value 0 means none */
|
||||||
|
lvp(is_locked_LVP, "lv_is_locked", NULL)
|
||||||
|
lvp(is_partial_LVP, "lv_is_partial", NULL)
|
||||||
|
lvp(is_virtual_LVP, "lv_is_virtual", NULL)
|
||||||
|
lvp(is_merging_LVP, "lv_is_merging", NULL)
|
||||||
|
lvp(is_merging_origin_LVP, "lv_is_merging_origin", NULL)
|
||||||
|
lvp(is_converting_LVP, "lv_is_converting", NULL)
|
||||||
|
lvp(is_external_origin_LVP, "lv_is_external_origin", NULL)
|
||||||
|
lvp(is_virtual_origin_LVP, "lv_is_virtual_origin", NULL)
|
||||||
|
lvp(is_not_synced_LVP, "lv_is_not_synced", NULL)
|
||||||
|
lvp(is_pending_delete_LVP, "lv_is_pending_delete", NULL)
|
||||||
|
lvp(is_error_when_full_LVP, "lv_is_error_when_full", NULL)
|
||||||
|
lvp(is_pvmove_LVP, "lv_is_pvmove", NULL)
|
||||||
|
lvp(is_removed_LVP, "lv_is_removed", NULL)
|
||||||
|
lvp(is_vg_writable_LVP, "lv_is_vg_writable", NULL)
|
||||||
|
|
||||||
|
/* kinds of sub LV */
|
||||||
|
lvp(is_thinpool_data_LVP, "lv_is_thinpool_data", NULL)
|
||||||
|
lvp(is_thinpool_metadata_LVP, "lv_is_thinpool_metadata", NULL)
|
||||||
|
lvp(is_cachepool_data_LVP, "lv_is_cachepool_data", NULL)
|
||||||
|
lvp(is_cachepool_metadata_LVP, "lv_is_cachepool_metadata", NULL)
|
||||||
|
lvp(is_mirror_image_LVP, "lv_is_mirror_image", NULL)
|
||||||
|
lvp(is_mirror_log_LVP, "lv_is_mirror_log", NULL)
|
||||||
|
lvp(is_raid_image_LVP, "lv_is_raid_image", NULL)
|
||||||
|
lvp(is_raid_metadata_LVP, "lv_is_raid_metadata", NULL)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* is_thick_origin should be used instead of is_origin
|
||||||
|
* is_thick_snapshot is generally used as LV_snapshot from lv_types.h
|
||||||
|
*/
|
||||||
|
lvp(is_origin_LVP, "lv_is_origin", NULL)
|
||||||
|
lvp(is_thick_origin_LVP, "lv_is_thick_origin", NULL)
|
||||||
|
lvp(is_thick_snapshot_LVP, "lv_is_thick_snapshot", NULL)
|
||||||
|
lvp(is_thin_origin_LVP, "lv_is_thin_origin", NULL)
|
||||||
|
lvp(is_thin_snapshot_LVP, "lv_is_thin_snapshot", NULL)
|
||||||
|
|
||||||
|
lvp(is_cache_origin_LVP, "lv_is_cache_origin", NULL)
|
||||||
|
lvp(is_merging_cow_LVP, "lv_is_merging_cow", NULL)
|
||||||
|
lvp(is_cow_covering_origin_LVP, "lv_is_cow_covering_origin", NULL)
|
||||||
|
lvp(is_visible_LVP, "lv_is_visible", NULL)
|
||||||
|
lvp(is_historical_LVP, "lv_is_historical", NULL)
|
||||||
|
lvp(is_raid_with_tracking_LVP, "lv_is_raid_with_tracking", NULL)
|
||||||
|
lvp(LVP_COUNT, "", NULL)
|
||||||
|
|
32
tools/lv_types.h
Normal file
32
tools/lv_types.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* LV types used in command definitions. The type strings are used
|
||||||
|
* as LV suffixes, e.g. LV_type or LV_type1_type2.
|
||||||
|
*
|
||||||
|
* The final NULL arg can be replaced with lv_is_type() functions
|
||||||
|
* if the current lv_is_type #defines become functions and are
|
||||||
|
* moved to tools.h
|
||||||
|
*
|
||||||
|
* Until then, the lv_is_type() functions are called indirectly
|
||||||
|
* through _lv_is_type().
|
||||||
|
*/
|
||||||
|
|
||||||
|
lvt(LVT_NONE, "", NULL)
|
||||||
|
lvt(linear_LVT, "linear", NULL)
|
||||||
|
lvt(striped_LVT, "striped", NULL)
|
||||||
|
lvt(snapshot_LVT, "snapshot", NULL) /* lv_is_cow, lv_is_thick_snapshot */
|
||||||
|
lvt(thin_LVT, "thin", NULL)
|
||||||
|
lvt(thinpool_LVT, "thinpool", NULL)
|
||||||
|
lvt(cache_LVT, "cache", NULL)
|
||||||
|
lvt(cachepool_LVT, "cachepool", NULL)
|
||||||
|
lvt(mirror_LVT, "mirror", NULL)
|
||||||
|
lvt(raid_LVT, "raid", NULL)
|
||||||
|
lvt(raid0_LVT, "raid0", NULL)
|
||||||
|
lvt(raid1_LVT, "raid1", NULL)
|
||||||
|
lvt(raid4_LVT, "raid4", NULL)
|
||||||
|
lvt(raid5_LVT, "raid5", NULL)
|
||||||
|
lvt(raid6_LVT, "raid6", NULL)
|
||||||
|
lvt(raid10_LVT, "raid10", NULL)
|
||||||
|
lvt(LVT_COUNT, "", NULL)
|
||||||
|
|
736
tools/lvchange.c
736
tools/lvchange.c
@@ -25,12 +25,6 @@ static int _lvchange_permission(struct cmd_context *cmd,
|
|||||||
|
|
||||||
lv_access = arg_uint_value(cmd, permission_ARG, 0);
|
lv_access = arg_uint_value(cmd, permission_ARG, 0);
|
||||||
|
|
||||||
if (lv_is_external_origin(lv)) {
|
|
||||||
log_error("Cannot change permissions of external origin %s.",
|
|
||||||
display_lvname(lv));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(lv_access & LVM_WRITE) && !(lv->status & LVM_WRITE)) {
|
if (!(lv_access & LVM_WRITE) && !(lv->status & LVM_WRITE)) {
|
||||||
/* Refresh if it's read-only in metadata but read-write in kernel */
|
/* Refresh if it's read-only in metadata but read-write in kernel */
|
||||||
if (lv_info(cmd, lv, 0, &info, 0, 0) && info.exists && !info.read_only) {
|
if (lv_info(cmd, lv, 0, &info, 0, 0) && info.exists && !info.read_only) {
|
||||||
@@ -63,20 +57,6 @@ static int _lvchange_permission(struct cmd_context *cmd,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Not allowed to change permissions on RAID sub-LVs directly */
|
|
||||||
if (lv_is_raid_metadata(lv) || lv_is_raid_image(lv)) {
|
|
||||||
log_error("Cannot change permissions of RAID %s %s.",
|
|
||||||
lv_is_raid_image(lv) ? "image" : "metadata area",
|
|
||||||
display_lvname(lv));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(lv_access & LVM_WRITE) && lv_is_thin_pool(lv)) {
|
|
||||||
log_error("Change permissions of thin pool %s not yet supported.",
|
|
||||||
display_lvname(lv));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lv_access & LVM_WRITE) {
|
if (lv_access & LVM_WRITE) {
|
||||||
lv->status |= LVM_WRITE;
|
lv->status |= LVM_WRITE;
|
||||||
log_verbose("Setting logical volume %s read/write.",
|
log_verbose("Setting logical volume %s read/write.",
|
||||||
@@ -100,12 +80,6 @@ static int _lvchange_pool_update(struct cmd_context *cmd,
|
|||||||
unsigned val;
|
unsigned val;
|
||||||
thin_discards_t discards;
|
thin_discards_t discards;
|
||||||
|
|
||||||
if (!lv_is_thin_pool(lv)) {
|
|
||||||
log_error("Logical volume %s is not a thin pool.",
|
|
||||||
display_lvname(lv));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arg_is_set(cmd, discards_ARG)) {
|
if (arg_is_set(cmd, discards_ARG)) {
|
||||||
discards = (thin_discards_t) arg_uint_value(cmd, discards_ARG, THIN_DISCARDS_IGNORE);
|
discards = (thin_discards_t) arg_uint_value(cmd, discards_ARG, THIN_DISCARDS_IGNORE);
|
||||||
if (discards != first_seg(lv)->discards) {
|
if (discards != first_seg(lv)->discards) {
|
||||||
@@ -153,10 +127,6 @@ static int _lvchange_monitoring(struct cmd_context *cmd,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* do not monitor pvmove lv's */
|
|
||||||
if (lv_is_pvmove(lv))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if ((dmeventd_monitor_mode() != DMEVENTD_MONITOR_IGNORE) &&
|
if ((dmeventd_monitor_mode() != DMEVENTD_MONITOR_IGNORE) &&
|
||||||
!monitor_dev_for_events(cmd, lv, 0, dmeventd_monitor_mode()))
|
!monitor_dev_for_events(cmd, lv, 0, dmeventd_monitor_mode()))
|
||||||
return_0;
|
return_0;
|
||||||
@@ -280,20 +250,6 @@ static int attach_metadata_devices(struct lv_segment *seg, struct dm_list *list)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* lvchange_refresh
|
|
||||||
* @cmd
|
|
||||||
* @lv
|
|
||||||
*
|
|
||||||
* Suspend and resume a logical volume.
|
|
||||||
*/
|
|
||||||
static int _lvchange_refresh(struct cmd_context *cmd, struct logical_volume *lv)
|
|
||||||
{
|
|
||||||
log_verbose("Refreshing logical volume %s (if active).", display_lvname(lv));
|
|
||||||
|
|
||||||
return lv_refresh(cmd, lv);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _reactivate_lv(struct logical_volume *lv,
|
static int _reactivate_lv(struct logical_volume *lv,
|
||||||
int active, int exclusive)
|
int active, int exclusive)
|
||||||
{
|
{
|
||||||
@@ -326,23 +282,6 @@ static int _lvchange_resync(struct cmd_context *cmd, struct logical_volume *lv)
|
|||||||
|
|
||||||
dm_list_init(&device_list);
|
dm_list_init(&device_list);
|
||||||
|
|
||||||
if (seg_is_any_raid0(seg) ||
|
|
||||||
(!seg_is_mirror(seg) && !seg_is_raid(seg))) {
|
|
||||||
log_error("Unable to resync %s. It is not RAID4/5/6/10 or mirrored.",
|
|
||||||
display_lvname(lv));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lv_is_pvmove(lv)) {
|
|
||||||
log_error("Unable to resync pvmove volume %s.", display_lvname(lv));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lv_is_locked(lv)) {
|
|
||||||
log_error("Unable to resync locked volume %s.", display_lvname(lv));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lv_is_active_locally(lv)) {
|
if (lv_is_active_locally(lv)) {
|
||||||
if (!lv_check_not_in_use(lv, 1)) {
|
if (!lv_check_not_in_use(lv, 1)) {
|
||||||
log_error("Can't resync open logical volume %s.",
|
log_error("Can't resync open logical volume %s.",
|
||||||
@@ -691,15 +630,6 @@ static int _lvchange_cache(struct cmd_context *cmd, struct logical_volume *lv)
|
|||||||
|
|
||||||
if (lv_is_cache(lv))
|
if (lv_is_cache(lv))
|
||||||
pool_seg = first_seg(pool_seg->pool_lv);
|
pool_seg = first_seg(pool_seg->pool_lv);
|
||||||
else if (!lv_is_cache_pool(lv)) {
|
|
||||||
log_error("LV %s is not a cache LV.", display_lvname(lv));
|
|
||||||
(void) arg_from_list_is_set(cmd, "is supported only with cache or cache pool LVs",
|
|
||||||
cachemode_ARG,
|
|
||||||
cachepolicy_ARG,
|
|
||||||
cachesettings_ARG,
|
|
||||||
-1);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!get_cache_params(cmd, &mode, &name, &settings))
|
if (!get_cache_params(cmd, &mode, &name, &settings))
|
||||||
goto_out;
|
goto_out;
|
||||||
@@ -759,12 +689,6 @@ static int _lvchange_rebuild(struct logical_volume *lv)
|
|||||||
struct arg_value_group_list *group;
|
struct arg_value_group_list *group;
|
||||||
struct volume_group *vg = lv->vg;
|
struct volume_group *vg = lv->vg;
|
||||||
struct cmd_context *cmd = vg->cmd;
|
struct cmd_context *cmd = vg->cmd;
|
||||||
struct lv_segment *raid_seg = first_seg(lv);
|
|
||||||
|
|
||||||
if (!seg_is_raid(raid_seg) || seg_is_any_raid0(raid_seg)) {
|
|
||||||
log_error("--rebuild can only be used with 'raid4/5/6/10' segment types.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(pv_count = arg_count(cmd, rebuild_ARG))) {
|
if (!(pv_count = arg_count(cmd, rebuild_ARG))) {
|
||||||
log_error("No --rebuild found!");
|
log_error("No --rebuild found!");
|
||||||
@@ -815,12 +739,6 @@ static int _lvchange_writemostly(struct logical_volume *lv)
|
|||||||
struct cmd_context *cmd = lv->vg->cmd;
|
struct cmd_context *cmd = lv->vg->cmd;
|
||||||
struct lv_segment *raid_seg = first_seg(lv);
|
struct lv_segment *raid_seg = first_seg(lv);
|
||||||
|
|
||||||
if (!seg_is_raid1(raid_seg)) {
|
|
||||||
log_error("--write%s can only be used with 'raid1' segment type.",
|
|
||||||
arg_is_set(cmd, writemostly_ARG) ? "mostly" : "behind");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arg_is_set(cmd, writebehind_ARG))
|
if (arg_is_set(cmd, writebehind_ARG))
|
||||||
raid_seg->writebehind = arg_uint_value(cmd, writebehind_ARG, 0);
|
raid_seg->writebehind = arg_uint_value(cmd, writebehind_ARG, 0);
|
||||||
|
|
||||||
@@ -909,12 +827,6 @@ static int _lvchange_recovery_rate(struct logical_volume *lv)
|
|||||||
struct cmd_context *cmd = lv->vg->cmd;
|
struct cmd_context *cmd = lv->vg->cmd;
|
||||||
struct lv_segment *raid_seg = first_seg(lv);
|
struct lv_segment *raid_seg = first_seg(lv);
|
||||||
|
|
||||||
if (!seg_is_raid(raid_seg)) {
|
|
||||||
log_error("Unable to change the recovery rate of non-RAID "
|
|
||||||
"logical volume %s.", display_lvname(lv));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arg_is_set(cmd, minrecoveryrate_ARG))
|
if (arg_is_set(cmd, minrecoveryrate_ARG))
|
||||||
raid_seg->min_recovery_rate =
|
raid_seg->min_recovery_rate =
|
||||||
arg_uint_value(cmd, minrecoveryrate_ARG, 0) / 2;
|
arg_uint_value(cmd, minrecoveryrate_ARG, 0) / 2;
|
||||||
@@ -982,522 +894,25 @@ static int _lvchange_activation_skip(struct logical_volume *lv)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int _lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
|
|
||||||
struct processing_handle *handle __attribute__((unused)))
|
|
||||||
{
|
|
||||||
int doit = 0, docmds = 0;
|
|
||||||
struct logical_volume *origin;
|
|
||||||
char snaps_msg[128];
|
|
||||||
|
|
||||||
if (sigint_caught())
|
|
||||||
return_ECMD_FAILED;
|
|
||||||
|
|
||||||
if (!(lv->vg->status & LVM_WRITE) &&
|
|
||||||
arg_from_list_is_set(cmd, NULL,
|
|
||||||
alloc_ARG,
|
|
||||||
contiguous_ARG,
|
|
||||||
discards_ARG,
|
|
||||||
metadataprofile_ARG,
|
|
||||||
permission_ARG,
|
|
||||||
persistent_ARG,
|
|
||||||
profile_ARG,
|
|
||||||
readahead_ARG,
|
|
||||||
zero_ARG,
|
|
||||||
-1)) {
|
|
||||||
log_error("Only -a permitted with read-only volume group %s.",
|
|
||||||
lv->vg->name);
|
|
||||||
return ECMD_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lv_is_origin(lv) && !lv_is_thin_volume(lv) &&
|
|
||||||
arg_from_list_is_set(cmd, NULL,
|
|
||||||
alloc_ARG,
|
|
||||||
contiguous_ARG,
|
|
||||||
metadataprofile_ARG,
|
|
||||||
permission_ARG,
|
|
||||||
persistent_ARG,
|
|
||||||
profile_ARG,
|
|
||||||
readahead_ARG,
|
|
||||||
-1)) {
|
|
||||||
log_error("Can't change logical volume %s under snapshot.",
|
|
||||||
display_lvname(lv));
|
|
||||||
return ECMD_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lv_is_pvmove(lv)) {
|
|
||||||
log_error("Unable to change pvmove LV %s.", display_lvname(lv));
|
|
||||||
if (arg_is_set(cmd, activate_ARG))
|
|
||||||
log_error("Use 'pvmove --abort' to abandon a pvmove");
|
|
||||||
return ECMD_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lv_is_mirror_log(lv)) {
|
|
||||||
log_error("Unable to change mirror log LV %s directly.",
|
|
||||||
display_lvname(lv));
|
|
||||||
return ECMD_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lv_is_mirror_image(lv)) {
|
|
||||||
log_error("Unable to change mirror image LV %s directly.",
|
|
||||||
display_lvname(lv));
|
|
||||||
return ECMD_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If LV is sparse, activate origin instead */
|
|
||||||
if (arg_is_set(cmd, activate_ARG) && lv_is_cow(lv) &&
|
|
||||||
lv_is_virtual_origin(origin = origin_from_cow(lv)))
|
|
||||||
lv = origin;
|
|
||||||
|
|
||||||
/* Use cache origin LV for 'raid' actions */
|
|
||||||
if (lv_is_cache(lv) &&
|
|
||||||
arg_from_list_is_set(cmd, NULL,
|
|
||||||
/* FIXME: we want to support more ops here */
|
|
||||||
//resync_ARG,
|
|
||||||
syncaction_ARG,
|
|
||||||
-1)) {
|
|
||||||
lv = seg_lv(first_seg(lv), 0);
|
|
||||||
log_debug("Using cache origin volume %s for lvchange instead.",
|
|
||||||
display_lvname(lv));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((lv_is_thin_pool_data(lv) || lv_is_thin_pool_metadata(lv) ||
|
|
||||||
lv_is_cache_pool_data(lv) || lv_is_cache_pool_metadata(lv)) &&
|
|
||||||
!arg_is_set(cmd, activate_ARG) &&
|
|
||||||
!arg_is_set(cmd, permission_ARG) &&
|
|
||||||
!arg_is_set(cmd, setactivationskip_ARG))
|
|
||||||
/* Rest can be changed for stacked thin pool meta/data volumes */
|
|
||||||
;
|
|
||||||
else if (lv_is_cache_origin(lv) && lv_is_raid(lv)) {
|
|
||||||
if (vg_is_clustered(lv->vg)) {
|
|
||||||
log_error("Unable to change internal LV %s directly in a cluster.",
|
|
||||||
display_lvname(lv));
|
|
||||||
return ECMD_FAILED;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* FIXME: For now, we don't want to allow all kinds of
|
|
||||||
* operations on this cache origin sub-LV. We are going
|
|
||||||
* to restrict it to non-clustered, RAID. This way, we
|
|
||||||
* can change the syncaction as needed (e.g. initiate
|
|
||||||
* scrubbing).
|
|
||||||
*
|
|
||||||
* Later pass all 'cache' actions on cache origin.
|
|
||||||
*/
|
|
||||||
} else if (!lv_is_visible(lv) && !lv_is_virtual_origin(lv)) {
|
|
||||||
log_error("Unable to change internal LV %s directly.",
|
|
||||||
display_lvname(lv));
|
|
||||||
return ECMD_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lv_is_cow(lv) && arg_is_set(cmd, activate_ARG)) {
|
|
||||||
origin = origin_from_cow(lv);
|
|
||||||
if (origin->origin_count < 2)
|
|
||||||
snaps_msg[0] = '\0';
|
|
||||||
else if (dm_snprintf(snaps_msg, sizeof(snaps_msg),
|
|
||||||
" and %u other snapshot(s)",
|
|
||||||
origin->origin_count - 1) < 0) {
|
|
||||||
log_error("Failed to prepare message.");
|
|
||||||
return ECMD_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!arg_is_set(cmd, yes_ARG) &&
|
|
||||||
(yes_no_prompt("Change of snapshot %s will also change its "
|
|
||||||
"origin %s%s. Proceed? [y/n]: ",
|
|
||||||
display_lvname(lv), display_lvname(origin),
|
|
||||||
snaps_msg) == 'n')) {
|
|
||||||
log_error("Logical volume %s not changed.", display_lvname(lv));
|
|
||||||
return ECMD_FAILED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arg_is_set(cmd, errorwhenfull_ARG) && !lv_is_thin_pool(lv)) {
|
|
||||||
log_error("Option --errorwhenfull is only supported with thin pools.");
|
|
||||||
return ECMD_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arg_is_set(cmd, persistent_ARG) && lv_is_pool(lv)) {
|
|
||||||
log_error("Persistent major and minor numbers are not supported with pools.");
|
|
||||||
return ECMD_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!arg_is_set(cmd, activate_ARG) && !arg_is_set(cmd, refresh_ARG)) {
|
|
||||||
/*
|
|
||||||
* If a persistent lv lock already exists from activation
|
|
||||||
* (with the needed mode or higher), this will be a no-op.
|
|
||||||
* Otherwise, the lv lock will be taken as non-persistent
|
|
||||||
* and released when this command exits.
|
|
||||||
*
|
|
||||||
* FIXME: use "sh" if the options imply that the lvchange
|
|
||||||
* operation does not modify the LV.
|
|
||||||
*/
|
|
||||||
if (!lockd_lv(cmd, lv, "ex", 0)) {
|
|
||||||
stack;
|
|
||||||
return ECMD_FAILED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* FIXME: DEFAULT_BACKGROUND_POLLING should be "unspecified".
|
|
||||||
* If --poll is explicitly provided use it; otherwise polling
|
|
||||||
* should only be started if the LV is not already active. So:
|
|
||||||
* 1) change the activation code to say if the LV was actually activated
|
|
||||||
* 2) make polling of an LV tightly coupled with LV activation
|
|
||||||
*
|
|
||||||
* Do not initiate any polling if --sysinit option is used.
|
|
||||||
*/
|
|
||||||
init_background_polling(arg_is_set(cmd, sysinit_ARG) ? 0 :
|
|
||||||
arg_int_value(cmd, poll_ARG,
|
|
||||||
DEFAULT_BACKGROUND_POLLING));
|
|
||||||
|
|
||||||
/* access permission change */
|
|
||||||
if (arg_is_set(cmd, permission_ARG)) {
|
|
||||||
if (!archive(lv->vg))
|
|
||||||
return_ECMD_FAILED;
|
|
||||||
doit += _lvchange_permission(cmd, lv);
|
|
||||||
docmds++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* allocation policy change */
|
|
||||||
if (arg_is_set(cmd, contiguous_ARG) || arg_is_set(cmd, alloc_ARG)) {
|
|
||||||
if (!archive(lv->vg))
|
|
||||||
return_ECMD_FAILED;
|
|
||||||
doit += _lvchange_alloc(cmd, lv);
|
|
||||||
docmds++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* error when full change */
|
|
||||||
if (arg_is_set(cmd, errorwhenfull_ARG)) {
|
|
||||||
if (!archive(lv->vg))
|
|
||||||
return_ECMD_FAILED;
|
|
||||||
doit += _lvchange_errorwhenfull(cmd, lv);
|
|
||||||
docmds++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* read ahead sector change */
|
|
||||||
if (arg_is_set(cmd, readahead_ARG)) {
|
|
||||||
if (!archive(lv->vg))
|
|
||||||
return_ECMD_FAILED;
|
|
||||||
doit += _lvchange_readahead(cmd, lv);
|
|
||||||
docmds++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* persistent device number change */
|
|
||||||
if (arg_is_set(cmd, persistent_ARG)) {
|
|
||||||
if (!archive(lv->vg))
|
|
||||||
return_ECMD_FAILED;
|
|
||||||
doit += _lvchange_persistent(cmd, lv);
|
|
||||||
docmds++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arg_is_set(cmd, discards_ARG) ||
|
|
||||||
arg_is_set(cmd, zero_ARG)) {
|
|
||||||
if (!archive(lv->vg))
|
|
||||||
return_ECMD_FAILED;
|
|
||||||
doit += _lvchange_pool_update(cmd, lv);
|
|
||||||
docmds++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add tag */
|
|
||||||
if (arg_is_set(cmd, addtag_ARG)) {
|
|
||||||
if (!archive(lv->vg))
|
|
||||||
return_ECMD_FAILED;
|
|
||||||
doit += _lvchange_tag(cmd, lv, addtag_ARG);
|
|
||||||
docmds++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* del tag */
|
|
||||||
if (arg_is_set(cmd, deltag_ARG)) {
|
|
||||||
if (!archive(lv->vg))
|
|
||||||
return_ECMD_FAILED;
|
|
||||||
doit += _lvchange_tag(cmd, lv, deltag_ARG);
|
|
||||||
docmds++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* rebuild selected PVs */
|
|
||||||
if (arg_is_set(cmd, rebuild_ARG)) {
|
|
||||||
if (!archive(lv->vg))
|
|
||||||
return_ECMD_FAILED;
|
|
||||||
doit += _lvchange_rebuild(lv);
|
|
||||||
docmds++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* change writemostly/writebehind */
|
|
||||||
if (arg_is_set(cmd, writemostly_ARG) || arg_is_set(cmd, writebehind_ARG)) {
|
|
||||||
if (!archive(lv->vg))
|
|
||||||
return_ECMD_FAILED;
|
|
||||||
doit += _lvchange_writemostly(lv);
|
|
||||||
docmds++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* change [min|max]_recovery_rate */
|
|
||||||
if (arg_is_set(cmd, minrecoveryrate_ARG) ||
|
|
||||||
arg_is_set(cmd, maxrecoveryrate_ARG)) {
|
|
||||||
if (!archive(lv->vg))
|
|
||||||
return_ECMD_FAILED;
|
|
||||||
doit += _lvchange_recovery_rate(lv);
|
|
||||||
docmds++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* change configuration profile */
|
|
||||||
if (arg_is_set(cmd, profile_ARG) || arg_is_set(cmd, metadataprofile_ARG) ||
|
|
||||||
arg_is_set(cmd, detachprofile_ARG)) {
|
|
||||||
if (!archive(lv->vg))
|
|
||||||
return_ECMD_FAILED;
|
|
||||||
doit += _lvchange_profile(lv);
|
|
||||||
docmds++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arg_is_set(cmd, setactivationskip_ARG)) {
|
|
||||||
if (!archive(lv->vg))
|
|
||||||
return_ECMD_FAILED;
|
|
||||||
doit += _lvchange_activation_skip(lv);
|
|
||||||
docmds++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arg_is_set(cmd, cachemode_ARG) ||
|
|
||||||
arg_is_set(cmd, cachepolicy_ARG) || arg_is_set(cmd, cachesettings_ARG)) {
|
|
||||||
if (!archive(lv->vg))
|
|
||||||
return_ECMD_FAILED;
|
|
||||||
doit += _lvchange_cache(cmd, lv);
|
|
||||||
docmds++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doit)
|
|
||||||
log_print_unless_silent("Logical volume %s changed.", display_lvname(lv));
|
|
||||||
|
|
||||||
if (arg_is_set(cmd, resync_ARG) &&
|
|
||||||
!_lvchange_resync(cmd, lv))
|
|
||||||
return_ECMD_FAILED;
|
|
||||||
|
|
||||||
if (arg_is_set(cmd, syncaction_ARG)) {
|
|
||||||
struct lv_segment *seg = first_seg(lv);
|
|
||||||
|
|
||||||
if (seg_is_any_raid0(seg)) {
|
|
||||||
log_error("Unable to sync raid0 LV %s.", display_lvname(lv));
|
|
||||||
return_ECMD_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!lv_raid_message(lv, arg_str_value(cmd, syncaction_ARG, NULL)))
|
|
||||||
return_ECMD_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* activation change */
|
|
||||||
if (arg_is_set(cmd, activate_ARG)) {
|
|
||||||
if (!_lvchange_activate(cmd, lv))
|
|
||||||
return_ECMD_FAILED;
|
|
||||||
} else if (arg_is_set(cmd, refresh_ARG)) {
|
|
||||||
if (!_lvchange_refresh(cmd, lv))
|
|
||||||
return_ECMD_FAILED;
|
|
||||||
} else {
|
|
||||||
if (arg_is_set(cmd, monitor_ARG) &&
|
|
||||||
!_lvchange_monitoring(cmd, lv))
|
|
||||||
return_ECMD_FAILED;
|
|
||||||
|
|
||||||
if (arg_is_set(cmd, poll_ARG) &&
|
|
||||||
!_lvchange_background_polling(cmd, lv))
|
|
||||||
return_ECMD_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doit != docmds)
|
|
||||||
return_ECMD_FAILED;
|
|
||||||
|
|
||||||
return ECMD_PROCESSED;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lvchange(struct cmd_context *cmd, int argc, char **argv)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Options that update metadata should be listed in one of
|
|
||||||
* the two lists below (i.e. options other than -a, --refresh,
|
|
||||||
* --monitor or --poll).
|
|
||||||
*/
|
|
||||||
int update_partial_safe = /* options safe to update if partial */
|
|
||||||
arg_from_list_is_set(cmd, NULL,
|
|
||||||
addtag_ARG,
|
|
||||||
contiguous_ARG,
|
|
||||||
deltag_ARG,
|
|
||||||
detachprofile_ARG,
|
|
||||||
metadataprofile_ARG,
|
|
||||||
permission_ARG,
|
|
||||||
persistent_ARG,
|
|
||||||
profile_ARG,
|
|
||||||
readahead_ARG,
|
|
||||||
setactivationskip_ARG,
|
|
||||||
-1);
|
|
||||||
int update_partial_unsafe =
|
|
||||||
arg_from_list_is_set(cmd, NULL,
|
|
||||||
alloc_ARG,
|
|
||||||
cachemode_ARG,
|
|
||||||
cachepolicy_ARG,
|
|
||||||
cachesettings_ARG,
|
|
||||||
discards_ARG,
|
|
||||||
errorwhenfull_ARG,
|
|
||||||
maxrecoveryrate_ARG,
|
|
||||||
minrecoveryrate_ARG,
|
|
||||||
rebuild_ARG,
|
|
||||||
resync_ARG,
|
|
||||||
syncaction_ARG,
|
|
||||||
writebehind_ARG,
|
|
||||||
writemostly_ARG,
|
|
||||||
zero_ARG,
|
|
||||||
-1);
|
|
||||||
int update = update_partial_safe || update_partial_unsafe;
|
|
||||||
|
|
||||||
if (!update &&
|
|
||||||
!arg_is_set(cmd, activate_ARG) && !arg_is_set(cmd, refresh_ARG) &&
|
|
||||||
!arg_is_set(cmd, monitor_ARG) && !arg_is_set(cmd, poll_ARG)) {
|
|
||||||
log_error("Need 1 or more of -a, -C, -M, -p, -r, -Z, "
|
|
||||||
"--resync, --refresh, --alloc, --addtag, --deltag, "
|
|
||||||
"--monitor, --poll or --discards");
|
|
||||||
return EINVALID_CMD_LINE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((arg_is_set(cmd, profile_ARG) || arg_is_set(cmd, metadataprofile_ARG)) &&
|
|
||||||
arg_is_set(cmd, detachprofile_ARG)) {
|
|
||||||
log_error("Only one of --metadataprofile and --detachprofile permitted.");
|
|
||||||
return EINVALID_CMD_LINE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arg_is_set(cmd, activate_ARG) && arg_is_set(cmd, refresh_ARG)) {
|
|
||||||
log_error("Only one of -a and --refresh permitted.");
|
|
||||||
return EINVALID_CMD_LINE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((arg_is_set(cmd, ignorelockingfailure_ARG) ||
|
|
||||||
arg_is_set(cmd, sysinit_ARG)) && update) {
|
|
||||||
log_error("Only -a permitted with --ignorelockingfailure and --sysinit");
|
|
||||||
return EINVALID_CMD_LINE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!update || !update_partial_unsafe)
|
|
||||||
cmd->handles_missing_pvs = 1;
|
|
||||||
|
|
||||||
if (!argc && !arg_is_set(cmd, select_ARG)) {
|
|
||||||
log_error("Please give logical volume path(s) or use --select for selection.");
|
|
||||||
return EINVALID_CMD_LINE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((arg_is_set(cmd, minor_ARG) || arg_is_set(cmd, major_ARG)) &&
|
|
||||||
!arg_is_set(cmd, persistent_ARG)) {
|
|
||||||
log_error("--major and --minor require -My.");
|
|
||||||
return EINVALID_CMD_LINE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arg_is_set(cmd, minor_ARG) && argc != 1) {
|
|
||||||
log_error("Only give one logical volume when specifying minor.");
|
|
||||||
return EINVALID_CMD_LINE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arg_is_set(cmd, contiguous_ARG) && arg_is_set(cmd, alloc_ARG)) {
|
|
||||||
log_error("Only one of --alloc and --contiguous permitted.");
|
|
||||||
return EINVALID_CMD_LINE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arg_is_set(cmd, poll_ARG) && arg_is_set(cmd, sysinit_ARG)) {
|
|
||||||
log_error("Only one of --poll and --sysinit permitted.");
|
|
||||||
return EINVALID_CMD_LINE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If --sysinit -aay is used and at the same time lvmetad is used,
|
|
||||||
* we want to rely on autoactivation to take place. Also, we
|
|
||||||
* need to take special care here as lvmetad service does
|
|
||||||
* not neet to be running at this moment yet - it could be
|
|
||||||
* just too early during system initialization time.
|
|
||||||
*/
|
|
||||||
if (arg_is_set(cmd, sysinit_ARG) && (arg_uint_value(cmd, activate_ARG, 0) == CHANGE_AAY)) {
|
|
||||||
if (lvmetad_used()) {
|
|
||||||
log_warn("WARNING: lvmetad is active, skipping direct activation during sysinit.");
|
|
||||||
return ECMD_PROCESSED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Include foreign VGs that contain active LVs.
|
|
||||||
* That shouldn't happen in general, but if it does by some
|
|
||||||
* mistake, then we want to allow those LVs to be deactivated.
|
|
||||||
*/
|
|
||||||
if (arg_is_set(cmd, activate_ARG))
|
|
||||||
cmd->include_active_foreign_vgs = 1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The default vg lock mode for lvchange is ex, but these options
|
|
||||||
* are cases where lvchange does not modify the vg, so they can use
|
|
||||||
* the sh lock mode.
|
|
||||||
*/
|
|
||||||
if (arg_is_set(cmd, activate_ARG) || arg_is_set(cmd, refresh_ARG)) {
|
|
||||||
cmd->lockd_vg_default_sh = 1;
|
|
||||||
/* Allow deactivating if locks fail. */
|
|
||||||
if (is_change_activating((activation_change_t)arg_uint_value(cmd, activate_ARG, CHANGE_AY)))
|
|
||||||
cmd->lockd_vg_enforce_sh = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return process_each_lv(cmd, argc, argv, NULL, NULL,
|
|
||||||
update ? READ_FOR_UPDATE : 0, NULL,
|
|
||||||
&_lvchange_single);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/*
|
/*
|
||||||
* Check if the status of the LV allows running lvchange.
|
* For each lvchange command definintion:
|
||||||
*
|
*
|
||||||
* FIXME: check for invalid VG/LV properties in a way that is not prone
|
* lvchange_foo_cmd(cmd, argc, argv);
|
||||||
* to missing some. Currently, there are some checks here, some in the
|
* . set cmd fields that apply to "foo"
|
||||||
* functions above, some in process_each, and some may be missing.
|
* . set any other things that affect behavior of process_each
|
||||||
|
* . process_each_lv(_lvchange_foo_single);
|
||||||
|
*
|
||||||
|
* _lvchange_foo_single(lv);
|
||||||
|
* . _lvchange_foo(lv);
|
||||||
|
* . (or all the code could live in the _single fn)
|
||||||
*/
|
*/
|
||||||
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,
|
static int _lvchange_properties_single(struct cmd_context *cmd,
|
||||||
struct logical_volume *lv,
|
struct logical_volume *lv,
|
||||||
struct processing_handle *handle)
|
struct processing_handle *handle)
|
||||||
{
|
{
|
||||||
int doit = 0, docmds = 0;
|
int doit = 0, docmds = 0;
|
||||||
|
int i, opt_enum;
|
||||||
/* FIXME: sort out hidden/internal LVs, e.g. _lvchange_hidden_is_valid() */
|
|
||||||
|
|
||||||
if (!_lvchange_status_is_valid(cmd, lv))
|
|
||||||
return_ECMD_FAILED;
|
|
||||||
|
|
||||||
if (arg_is_set(cmd, persistent_ARG) && lv_is_pool(lv)) {
|
|
||||||
log_error("Operation not permitted on LV %s: persistent device numbers are not supported with pools.",
|
|
||||||
display_lvname(lv));
|
|
||||||
return ECMD_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If a persistent lv lock already exists from activation
|
* If a persistent lv lock already exists from activation
|
||||||
@@ -1582,6 +997,7 @@ static int _lvchange_properties_single(struct cmd_context *cmd,
|
|||||||
default:
|
default:
|
||||||
log_error(INTERNAL_ERROR "Failed to check for option %s",
|
log_error(INTERNAL_ERROR "Failed to check for option %s",
|
||||||
arg_long_option_name(i));
|
arg_long_option_name(i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (doit)
|
if (doit)
|
||||||
@@ -1595,13 +1011,12 @@ static int _lvchange_properties_single(struct cmd_context *cmd,
|
|||||||
|
|
||||||
int lvchange_properties_cmd(struct cmd_context *cmd, int argc, char **argv)
|
int lvchange_properties_cmd(struct cmd_context *cmd, int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct processing_handle *handle = init_processing_handle(cmd, NULL);
|
/*
|
||||||
int ret;
|
* A command def rule allows only some options when LV is partial,
|
||||||
|
* so handles_missing_pvs will only affect those.
|
||||||
ret = process_each_lv(cmd, argc, argv, NULL, NULL, READ_FOR_UPDATE, handle, _lvchange_properties_single);
|
*/
|
||||||
|
cmd->handles_missing_pvs = 1;
|
||||||
destroy_processing_handle(cmd, handle);
|
return process_each_lv(cmd, argc, argv, NULL, NULL, READ_FOR_UPDATE, NULL, _lvchange_properties_single);
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _lvchange_activate_single(struct cmd_context *cmd,
|
static int _lvchange_activate_single(struct cmd_context *cmd,
|
||||||
@@ -1611,11 +1026,6 @@ static int _lvchange_activate_single(struct cmd_context *cmd,
|
|||||||
struct logical_volume *origin;
|
struct logical_volume *origin;
|
||||||
char snaps_msg[128];
|
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 */
|
/* FIXME: untangle the proper logic for cow / sparse / virtual origin */
|
||||||
|
|
||||||
/* If LV is sparse, activate origin instead */
|
/* If LV is sparse, activate origin instead */
|
||||||
@@ -1665,8 +1075,6 @@ static int _lvchange_activate_single(struct cmd_context *cmd,
|
|||||||
|
|
||||||
int lvchange_activate_cmd(struct cmd_context *cmd, int argc, char **argv)
|
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->handles_missing_pvs = 1;
|
||||||
cmd->lockd_vg_default_sh = 1;
|
cmd->lockd_vg_default_sh = 1;
|
||||||
|
|
||||||
@@ -1681,24 +1089,16 @@ int lvchange_activate_cmd(struct cmd_context *cmd, int argc, char **argv)
|
|||||||
if (is_change_activating((activation_change_t)arg_uint_value(cmd, activate_ARG, CHANGE_AY)))
|
if (is_change_activating((activation_change_t)arg_uint_value(cmd, activate_ARG, CHANGE_AY)))
|
||||||
cmd->lockd_vg_enforce_sh = 1;
|
cmd->lockd_vg_enforce_sh = 1;
|
||||||
|
|
||||||
ret = process_each_lv(cmd, argc, argv, NULL, NULL, 0, handle, _lvchange_activate_single);
|
return process_each_lv(cmd, argc, argv, NULL, NULL, 0, NULL, _lvchange_activate_single);
|
||||||
|
|
||||||
destroy_processing_handle(cmd, handle);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _lvchange_refresh_single(struct cmd_context *cmd,
|
static int _lvchange_refresh_single(struct cmd_context *cmd,
|
||||||
struct logical_volume *lv,
|
struct logical_volume *lv,
|
||||||
struct processing_handle *handle)
|
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));
|
log_verbose("Refreshing logical volume %s (if active).", display_lvname(lv));
|
||||||
|
|
||||||
if (!_lv_refresh(cmd, lv))
|
if (!lv_refresh(cmd, lv))
|
||||||
return_ECMD_FAILED;
|
return_ECMD_FAILED;
|
||||||
|
|
||||||
return ECMD_PROCESSED;
|
return ECMD_PROCESSED;
|
||||||
@@ -1706,16 +1106,98 @@ static int _lvchange_refresh_single(struct cmd_context *cmd,
|
|||||||
|
|
||||||
int lvchange_refresh_cmd(struct cmd_context *cmd, int argc, char **argv)
|
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->handles_missing_pvs = 1;
|
||||||
cmd->lockd_vg_default_sh = 1;
|
cmd->lockd_vg_default_sh = 1;
|
||||||
|
|
||||||
ret = process_each_lv(cmd, argc, argv, NULL, NULL, 0, handle, _lvchange_refresh_single);
|
return process_each_lv(cmd, argc, argv, NULL, NULL, 0, NULL, _lvchange_refresh_single);
|
||||||
|
}
|
||||||
destroy_processing_handle(cmd, handle);
|
|
||||||
return ret;
|
static int _lvchange_resync_single(struct cmd_context *cmd,
|
||||||
|
struct logical_volume *lv,
|
||||||
|
struct processing_handle *handle)
|
||||||
|
{
|
||||||
|
if (!_lvchange_resync(cmd, lv))
|
||||||
|
return_ECMD_FAILED;
|
||||||
|
|
||||||
|
return ECMD_PROCESSED;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lvchange_resync_cmd(struct cmd_context *cmd, int argc, char **argv)
|
||||||
|
{
|
||||||
|
return process_each_lv(cmd, argc, argv, NULL, NULL, READ_FOR_UPDATE, NULL, _lvchange_resync_single);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _lvchange_syncaction_single(struct cmd_context *cmd,
|
||||||
|
struct logical_volume *lv,
|
||||||
|
struct processing_handle *handle)
|
||||||
|
{
|
||||||
|
if (!lv_raid_message(lv, arg_str_value(cmd, syncaction_ARG, NULL)))
|
||||||
|
return_ECMD_FAILED;
|
||||||
|
|
||||||
|
return ECMD_PROCESSED;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lvchange_syncaction_cmd(struct cmd_context *cmd, int argc, char **argv)
|
||||||
|
{
|
||||||
|
return process_each_lv(cmd, argc, argv, NULL, NULL, READ_FOR_UPDATE, NULL, _lvchange_syncaction_single);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _lvchange_rebuild_single(struct cmd_context *cmd,
|
||||||
|
struct logical_volume *lv,
|
||||||
|
struct processing_handle *handle)
|
||||||
|
{
|
||||||
|
if (!_lvchange_rebuild(lv))
|
||||||
|
return_ECMD_FAILED;
|
||||||
|
|
||||||
|
return ECMD_PROCESSED;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lvchange_rebuild_cmd(struct cmd_context *cmd, int argc, char **argv)
|
||||||
|
{
|
||||||
|
return process_each_lv(cmd, argc, argv, NULL, NULL, READ_FOR_UPDATE, NULL, _lvchange_rebuild_single);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _lvchange_monitor_poll_single(struct cmd_context *cmd,
|
||||||
|
struct logical_volume *lv,
|
||||||
|
struct processing_handle *handle)
|
||||||
|
{
|
||||||
|
if (arg_is_set(cmd, monitor_ARG) &&
|
||||||
|
!_lvchange_monitoring(cmd, lv))
|
||||||
|
return_ECMD_FAILED;
|
||||||
|
|
||||||
|
if (arg_is_set(cmd, poll_ARG) &&
|
||||||
|
!_lvchange_background_polling(cmd, lv))
|
||||||
|
return_ECMD_FAILED;
|
||||||
|
|
||||||
|
return ECMD_PROCESSED;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lvchange_monitor_poll_cmd(struct cmd_context *cmd, int argc, char **argv)
|
||||||
|
{
|
||||||
|
cmd->handles_missing_pvs = 1;
|
||||||
|
return process_each_lv(cmd, argc, argv, NULL, NULL, 0, NULL, _lvchange_monitor_poll_single);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _lvchange_persistent_single(struct cmd_context *cmd,
|
||||||
|
struct logical_volume *lv,
|
||||||
|
struct processing_handle *handle)
|
||||||
|
{
|
||||||
|
if (!_lvchange_persistent(cmd, lv))
|
||||||
|
return_ECMD_FAILED;
|
||||||
|
|
||||||
|
return ECMD_PROCESSED;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lvchange_persistent_cmd(struct cmd_context *cmd, int argc, char **argv)
|
||||||
|
{
|
||||||
|
cmd->handles_missing_pvs = 1;
|
||||||
|
return process_each_lv(cmd, argc, argv, NULL, NULL, READ_FOR_UPDATE, NULL, _lvchange_persistent_single);
|
||||||
|
}
|
||||||
|
|
||||||
|
int lvchange(struct cmd_context *cmd, int argc, char **argv)
|
||||||
|
{
|
||||||
|
log_error(INTERNAL_ERROR "Missing function for command definition %s.",
|
||||||
|
cmd->command->command_line_id);
|
||||||
|
return ECMD_FAILED;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
1129
tools/lvconvert.c
1129
tools/lvconvert.c
File diff suppressed because it is too large
Load Diff
@@ -1054,6 +1054,12 @@ static int _lvcreate_params(struct cmd_context *cmd,
|
|||||||
return 0;
|
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)) {
|
if (segtype_is_raid10(lp->segtype) && !(lp->target_attr & RAID_FEATURE_RAID10)) {
|
||||||
log_error("RAID module does not support RAID10.");
|
log_error("RAID module does not support RAID10.");
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -79,6 +79,25 @@ struct command_name command_names[MAX_COMMAND_NAMES] = {
|
|||||||
#undef xx
|
#undef xx
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Table of LV properties
|
||||||
|
*/
|
||||||
|
static struct lv_props _lv_props[LVP_COUNT + 1] = {
|
||||||
|
#define lvp(a, b, c) {a, b, c},
|
||||||
|
#include "lv_props.h"
|
||||||
|
#undef lvp
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Table of LV types
|
||||||
|
*/
|
||||||
|
static struct lv_types _lv_types[LVT_COUNT + 1] = {
|
||||||
|
#define lvt(a, b, c) {a, b, c},
|
||||||
|
#include "lv_types.h"
|
||||||
|
#undef lvt
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Table of valid command lines
|
* Table of valid command lines
|
||||||
*/
|
*/
|
||||||
@@ -94,6 +113,24 @@ static struct cmdline_context _cmdline;
|
|||||||
*/
|
*/
|
||||||
struct command_function command_functions[COMMAND_ID_COUNT] = {
|
struct command_function command_functions[COMMAND_ID_COUNT] = {
|
||||||
{ lvmconfig_general_CMD, lvmconfig },
|
{ lvmconfig_general_CMD, lvmconfig },
|
||||||
|
{ lvchange_properties_CMD, lvchange_properties_cmd },
|
||||||
|
{ lvchange_resync_CMD, lvchange_resync_cmd },
|
||||||
|
{ lvchange_syncaction_CMD, lvchange_syncaction_cmd },
|
||||||
|
{ lvchange_rebuild_CMD, lvchange_rebuild_cmd },
|
||||||
|
{ lvchange_activate_CMD, lvchange_activate_cmd },
|
||||||
|
{ lvchange_refresh_CMD, lvchange_refresh_cmd },
|
||||||
|
{ lvchange_monitor_CMD, lvchange_monitor_poll_cmd },
|
||||||
|
{ lvchange_poll_CMD, lvchange_monitor_poll_cmd },
|
||||||
|
{ lvchange_persistent_CMD, lvchange_persistent_cmd },
|
||||||
|
|
||||||
|
/* lvconvert utilities related to repair. */
|
||||||
|
{ lvconvert_repair_pvs_or_thinpool_CMD, lvconvert_repair_pvs_or_thinpool_cmd },
|
||||||
|
{ lvconvert_replace_pv_CMD, lvconvert_replace_pv_cmd },
|
||||||
|
|
||||||
|
/* lvconvert utilities related to snapshots. */
|
||||||
|
{ lvconvert_split_cow_snapshot_CMD, lvconvert_split_snapshot_cmd },
|
||||||
|
{ lvconvert_merge_snapshot_CMD, lvconvert_merge_snapshot_cmd },
|
||||||
|
{ lvconvert_combine_split_snapshot_CMD, lvconvert_combine_split_snapshot_cmd },
|
||||||
};
|
};
|
||||||
#if 0
|
#if 0
|
||||||
/* all raid-related type conversions */
|
/* all raid-related type conversions */
|
||||||
@@ -115,13 +152,9 @@ struct command_function command_functions[COMMAND_ID_COUNT] = {
|
|||||||
{ lvconvert_split_and_delete_cachepool_CMD, lvconvert_split_and_delete_cachepool_fn },
|
{ lvconvert_split_and_delete_cachepool_CMD, lvconvert_split_and_delete_cachepool_fn },
|
||||||
{ lvconvert_swap_pool_metadata_CMD, lvconvert_swap_pool_metadata_fn },
|
{ lvconvert_swap_pool_metadata_CMD, lvconvert_swap_pool_metadata_fn },
|
||||||
|
|
||||||
/* utilities related to snapshots and repair. */
|
/* other misc. */
|
||||||
|
|
||||||
{ lvconvert_merge_CMD, lvconvert_merge_fn },
|
{ lvconvert_merge_CMD, lvconvert_merge_fn },
|
||||||
{ lvconvert_combine_split_snapshot_CMD, lvconvert_combine_split_snapshot_fn },
|
|
||||||
{ lvconvert_repair_pvs_or_thinpool_CMD, lvconvert_repair_pvs_or_thinpool_fn },
|
|
||||||
{ lvconvert_replace_pv_CMD, lvconvert_replace_pv_fn },
|
|
||||||
{ lvconvert_split_cow_snapshot_CMD, lvconvert_split_cow_snapshot_fn },
|
|
||||||
{ lvconvert_poll_start_CMD, lvconvert_poll_start_fn },
|
{ lvconvert_poll_start_CMD, lvconvert_poll_start_fn },
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1079,6 +1112,20 @@ void lvm_register_commands(void)
|
|||||||
_set_valid_args_for_command_name(i);
|
_set_valid_args_for_command_name(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct lv_props *get_lv_prop(int lvp_enum)
|
||||||
|
{
|
||||||
|
if (!lvp_enum)
|
||||||
|
return NULL;
|
||||||
|
return &_lv_props[lvp_enum];
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lv_types *get_lv_type(int lvt_enum)
|
||||||
|
{
|
||||||
|
if (!lvt_enum)
|
||||||
|
return NULL;
|
||||||
|
return &_lv_types[lvt_enum];
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Also see merge_synonym(). The command definitions
|
* Also see merge_synonym(). The command definitions
|
||||||
* are written using just one variation of the option
|
* are written using just one variation of the option
|
||||||
@@ -1404,7 +1451,7 @@ static void _print_description(int ci)
|
|||||||
* set to match.
|
* set to match.
|
||||||
*
|
*
|
||||||
* required_pos_args[0].types & select_VAL means
|
* required_pos_args[0].types & select_VAL means
|
||||||
* cmd->argv[] in that pos can be NULL if arg_is_set(select_ARG)
|
* argv[] in that pos can be NULL if arg_is_set(select_ARG)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* The max number of unused options we keep track of to warn about */
|
/* The max number of unused options we keep track of to warn about */
|
||||||
@@ -1413,6 +1460,7 @@ static void _print_description(int ci)
|
|||||||
static struct command *_find_command(struct cmd_context *cmd, const char *path, int *argc, char **argv)
|
static struct command *_find_command(struct cmd_context *cmd, const char *path, int *argc, char **argv)
|
||||||
{
|
{
|
||||||
const char *name;
|
const char *name;
|
||||||
|
char buf[64];
|
||||||
int match_required, match_ro, match_rp, match_type, match_unused, mismatch_required;
|
int match_required, match_ro, match_rp, match_type, match_unused, mismatch_required;
|
||||||
int best_i = 0, best_required = 0, best_type = 0, best_unused = 0;
|
int best_i = 0, best_required = 0, best_type = 0, best_unused = 0;
|
||||||
int close_i = 0, close_ro = 0, close_type;
|
int close_i = 0, close_ro = 0, close_type;
|
||||||
@@ -1420,6 +1468,7 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path,
|
|||||||
int temp_unused_count;
|
int temp_unused_count;
|
||||||
int best_unused_options[MAX_UNUSED_COUNT] = { 0 };
|
int best_unused_options[MAX_UNUSED_COUNT] = { 0 };
|
||||||
int best_unused_count = 0;
|
int best_unused_count = 0;
|
||||||
|
int opts_match_count, opts_unmatch_count;
|
||||||
int ro, rp;
|
int ro, rp;
|
||||||
int i, j;
|
int i, j;
|
||||||
int opt_enum, opt_i;
|
int opt_enum, opt_i;
|
||||||
@@ -1644,7 +1693,55 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
/*
|
||||||
|
* Check any rules related to option combinations.
|
||||||
|
* Other rules are checked after VG is read.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (i = 0; i < commands[best_i].rule_count; i++) {
|
||||||
|
struct cmd_rule *rule;
|
||||||
|
rule = &commands[best_i].rules[i];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The rule wants to validate options (check_opts). That can be
|
||||||
|
* done here if the only qualification for the validation is
|
||||||
|
* other options (and not specific LV type or LV property which
|
||||||
|
* are not known here.)
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (rule->check_opts_count && !rule->lvt_bits && !rule->lvp_bits) {
|
||||||
|
/*
|
||||||
|
* When no opt is specified for applying the rule, then
|
||||||
|
* the rule is always applied, otherwise the rule is
|
||||||
|
* applied when the specific option is set.
|
||||||
|
*/
|
||||||
|
if (rule->opts_count &&
|
||||||
|
!opt_in_list_is_set(cmd, rule->opts, rule->opts_count, NULL, NULL))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
opt_in_list_is_set(cmd, rule->check_opts, rule->check_opts_count,
|
||||||
|
&opts_match_count, &opts_unmatch_count);
|
||||||
|
|
||||||
|
if (opts_match_count && (rule->rule == RULE_INVALID)) {
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
opt_array_to_str(cmd, rule->check_opts, rule->check_opts_count, buf, sizeof(buf));
|
||||||
|
log_error("Invalid options for command (%s %d): %s",
|
||||||
|
commands[best_i].command_line_id, best_i, buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts_unmatch_count && (rule->rule == RULE_REQUIRE)) {
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
opt_array_to_str(cmd, rule->check_opts, rule->check_opts_count, buf, sizeof(buf));
|
||||||
|
log_error("Required options for command (%s %d): %s",
|
||||||
|
commands[best_i].command_line_id, best_i, buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log_debug("command line id: %s %d", commands[best_i].command_line_id, best_i);
|
log_debug("command line id: %s %d", commands[best_i].command_line_id, best_i);
|
||||||
|
|
||||||
return &commands[best_i];
|
return &commands[best_i];
|
||||||
@@ -1703,7 +1800,7 @@ static int _usage(const char *name, int help_count)
|
|||||||
log_print(" be omitted if the --select option is used.");
|
log_print(" be omitted if the --select option is used.");
|
||||||
log_print(". --size Number can be replaced with --extents NumberExtents.");
|
log_print(". --size Number can be replaced with --extents NumberExtents.");
|
||||||
log_print(". When --name is omitted from lvcreate, a new LV name is");
|
log_print(". When --name is omitted from lvcreate, a new LV name is");
|
||||||
log_print(" generated with the \"lvol\" prefix and a unique numeral suffix.");
|
log_print(" generated with the \"lvol\" prefix and a unique numeric suffix.");
|
||||||
log_print(". The required VG parameter in lvcreate may be omitted when");
|
log_print(". The required VG parameter in lvcreate may be omitted when");
|
||||||
log_print(" the VG name is included in another option, e.g. --name VG/LV.");
|
log_print(" the VG name is included in another option, e.g. --name VG/LV.");
|
||||||
log_print(". For required options listed in parentheses, e.g. (--A, --B),");
|
log_print(". For required options listed in parentheses, e.g. (--A, --B),");
|
||||||
@@ -2542,6 +2639,12 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
|
|||||||
if (!(cmd->command = _find_command(cmd, cmd->name, &argc, argv)))
|
if (!(cmd->command = _find_command(cmd, cmd->name, &argc, argv)))
|
||||||
return EINVALID_CMD_LINE;
|
return EINVALID_CMD_LINE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remaining position args after command name and --options are removed.
|
||||||
|
*/
|
||||||
|
cmd->position_argc = argc;
|
||||||
|
cmd->position_argv = argv;
|
||||||
|
|
||||||
set_cmd_name(cmd->name);
|
set_cmd_name(cmd->name);
|
||||||
|
|
||||||
if (arg_is_set(cmd, backgroundfork_ARG)) {
|
if (arg_is_set(cmd, backgroundfork_ARG)) {
|
||||||
|
@@ -194,6 +194,9 @@ static int _pvscan_autoactivate_single(struct cmd_context *cmd, const char *vg_n
|
|||||||
if (vg_is_clustered(vg))
|
if (vg_is_clustered(vg))
|
||||||
return ECMD_PROCESSED;
|
return ECMD_PROCESSED;
|
||||||
|
|
||||||
|
if (vg_is_exported(vg))
|
||||||
|
return ECMD_PROCESSED;
|
||||||
|
|
||||||
if (is_lockd_type(vg->lock_type))
|
if (is_lockd_type(vg->lock_type))
|
||||||
return ECMD_PROCESSED;
|
return ECMD_PROCESSED;
|
||||||
|
|
||||||
|
625
tools/toollib.c
625
tools/toollib.c
@@ -2326,6 +2326,541 @@ static struct lv_segment _historical_lv_segment = {
|
|||||||
.origin_list = DM_LIST_HEAD_INIT(_historical_lv_segment.origin_list),
|
.origin_list = DM_LIST_HEAD_INIT(_historical_lv_segment.origin_list),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int opt_in_list_is_set(struct cmd_context *cmd, int *opts, int count,
|
||||||
|
int *match_count, int *unmatch_count)
|
||||||
|
{
|
||||||
|
int match = 0;
|
||||||
|
int unmatch = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
if (arg_is_set(cmd, opts[i]))
|
||||||
|
match++;
|
||||||
|
else
|
||||||
|
unmatch++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (match_count)
|
||||||
|
*match_count = match;
|
||||||
|
if (unmatch_count)
|
||||||
|
*unmatch_count = unmatch;
|
||||||
|
|
||||||
|
return match ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void opt_array_to_str(struct cmd_context *cmd, int *opts, int count,
|
||||||
|
char *buf, int len)
|
||||||
|
{
|
||||||
|
int pos = 0;
|
||||||
|
int ret;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
ret = snprintf(buf + pos, len - pos, "%s ", arg_long_option_name(opts[i]));
|
||||||
|
if (ret >= len - pos)
|
||||||
|
break;
|
||||||
|
pos += ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[len - 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lvp_bits_to_str(uint64_t bits, char *buf, int len)
|
||||||
|
{
|
||||||
|
struct lv_props *prop;
|
||||||
|
int lvp_enum;
|
||||||
|
int pos = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
for (lvp_enum = 0; lvp_enum < LVP_COUNT; lvp_enum++) {
|
||||||
|
if (!(prop = get_lv_prop(lvp_enum)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (lvp_bit_is_set(bits, lvp_enum)) {
|
||||||
|
ret = snprintf(buf + pos, len - pos, "%s ", prop->name);
|
||||||
|
if (ret >= len - pos)
|
||||||
|
break;
|
||||||
|
pos += ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf[len - 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lvt_bits_to_str(uint64_t bits, char *buf, int len)
|
||||||
|
{
|
||||||
|
struct lv_types *type;
|
||||||
|
int lvt_enum;
|
||||||
|
int pos = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
for (lvt_enum = 0; lvt_enum < LVT_COUNT; lvt_enum++) {
|
||||||
|
if (!(type = get_lv_type(lvt_enum)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (lvt_bit_is_set(bits, lvt_enum)) {
|
||||||
|
ret = snprintf(buf + pos, len - pos, "%s ", type->name);
|
||||||
|
if (ret >= len - pos)
|
||||||
|
break;
|
||||||
|
pos += ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf[len - 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the lv_prop function pointer used for lv_is_foo() #defines.
|
||||||
|
* Alternatively, lv_is_foo() could all be turned into functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int _lv_is_prop(struct cmd_context *cmd, struct logical_volume *lv, int lvp_enum)
|
||||||
|
{
|
||||||
|
switch (lvp_enum) {
|
||||||
|
case is_locked_LVP:
|
||||||
|
return lv_is_locked(lv);
|
||||||
|
case is_partial_LVP:
|
||||||
|
return lv_is_partial(lv);
|
||||||
|
case is_virtual_LVP:
|
||||||
|
return lv_is_virtual(lv);
|
||||||
|
case is_merging_LVP:
|
||||||
|
return lv_is_merging(lv);
|
||||||
|
case is_merging_origin_LVP:
|
||||||
|
return lv_is_merging_origin(lv);
|
||||||
|
case is_converting_LVP:
|
||||||
|
return lv_is_converting(lv);
|
||||||
|
case is_external_origin_LVP:
|
||||||
|
return lv_is_external_origin(lv);
|
||||||
|
case is_virtual_origin_LVP:
|
||||||
|
return lv_is_virtual_origin(lv);
|
||||||
|
case is_not_synced_LVP:
|
||||||
|
return lv_is_not_synced(lv);
|
||||||
|
case is_pending_delete_LVP:
|
||||||
|
return lv_is_pending_delete(lv);
|
||||||
|
case is_error_when_full_LVP:
|
||||||
|
return lv_is_error_when_full(lv);
|
||||||
|
case is_pvmove_LVP:
|
||||||
|
return lv_is_pvmove(lv);
|
||||||
|
case is_removed_LVP:
|
||||||
|
return lv_is_removed(lv);
|
||||||
|
case is_vg_writable_LVP:
|
||||||
|
return (lv->vg->status & LVM_WRITE) ? 1 : 0;
|
||||||
|
case is_thinpool_data_LVP:
|
||||||
|
return lv_is_thin_pool_data(lv);
|
||||||
|
case is_thinpool_metadata_LVP:
|
||||||
|
return lv_is_thin_pool_metadata(lv);
|
||||||
|
case is_cachepool_data_LVP:
|
||||||
|
return lv_is_cache_pool_data(lv);
|
||||||
|
case is_cachepool_metadata_LVP:
|
||||||
|
return lv_is_cache_pool_metadata(lv);
|
||||||
|
case is_mirror_image_LVP:
|
||||||
|
return lv_is_mirror_image(lv);
|
||||||
|
case is_mirror_log_LVP:
|
||||||
|
return lv_is_mirror_log(lv);
|
||||||
|
case is_raid_image_LVP:
|
||||||
|
return lv_is_raid_image(lv);
|
||||||
|
case is_raid_metadata_LVP:
|
||||||
|
return lv_is_raid_metadata(lv);
|
||||||
|
case is_origin_LVP: /* use lv_is_thick_origin */
|
||||||
|
return lv_is_origin(lv);
|
||||||
|
case is_thick_origin_LVP:
|
||||||
|
return lv_is_thick_origin(lv);
|
||||||
|
case is_thick_snapshot_LVP:
|
||||||
|
return lv_is_thick_snapshot(lv);
|
||||||
|
case is_thin_origin_LVP:
|
||||||
|
return lv_is_thin_origin(lv, NULL);
|
||||||
|
case is_thin_snapshot_LVP:
|
||||||
|
return lv_is_thin_snapshot(lv);
|
||||||
|
case is_cache_origin_LVP:
|
||||||
|
return lv_is_cache_origin(lv);
|
||||||
|
case is_merging_cow_LVP:
|
||||||
|
return lv_is_merging_cow(lv);
|
||||||
|
case is_cow_covering_origin_LVP:
|
||||||
|
return lv_is_cow_covering_origin(lv);
|
||||||
|
case is_visible_LVP:
|
||||||
|
return lv_is_visible(lv);
|
||||||
|
case is_historical_LVP:
|
||||||
|
return lv_is_historical(lv);
|
||||||
|
case is_raid_with_tracking_LVP:
|
||||||
|
return lv_is_raid_with_tracking(lv);
|
||||||
|
default:
|
||||||
|
log_error(INTERNAL_ERROR "unknown lv property value lvp_enum %d", lvp_enum);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if an LV matches a given LV type enum.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int _lv_is_type(struct cmd_context *cmd, struct logical_volume *lv, int lvt_enum)
|
||||||
|
{
|
||||||
|
struct lv_segment *seg = first_seg(lv);
|
||||||
|
|
||||||
|
switch (lvt_enum) {
|
||||||
|
case striped_LVT:
|
||||||
|
return seg_is_striped(seg);
|
||||||
|
case linear_LVT:
|
||||||
|
return seg_is_linear(seg);
|
||||||
|
case snapshot_LVT:
|
||||||
|
return lv_is_cow(lv);
|
||||||
|
case thin_LVT:
|
||||||
|
return lv_is_thin_volume(lv);
|
||||||
|
case thinpool_LVT:
|
||||||
|
return lv_is_thin_pool(lv);
|
||||||
|
case cache_LVT:
|
||||||
|
return lv_is_cache(lv);
|
||||||
|
case cachepool_LVT:
|
||||||
|
return lv_is_cache_pool(lv);
|
||||||
|
case mirror_LVT:
|
||||||
|
return lv_is_mirror(lv);
|
||||||
|
case raid_LVT:
|
||||||
|
return lv_is_raid(lv);
|
||||||
|
case raid0_LVT:
|
||||||
|
return seg_is_raid0(seg);
|
||||||
|
case raid1_LVT:
|
||||||
|
return seg_is_raid1(seg);
|
||||||
|
case raid4_LVT:
|
||||||
|
return seg_is_raid4(seg);
|
||||||
|
#if 0
|
||||||
|
case raid5_LVT:
|
||||||
|
return seg_is_raid5(seg);
|
||||||
|
case raid6_LVT:
|
||||||
|
return seg_is_raid6(seg);
|
||||||
|
#endif
|
||||||
|
case raid10_LVT:
|
||||||
|
return seg_is_raid10(seg);
|
||||||
|
default:
|
||||||
|
log_error(INTERNAL_ERROR "unknown lv type value lvt_enum %d", lvt_enum);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _get_lvt_enum(struct logical_volume *lv)
|
||||||
|
{
|
||||||
|
struct lv_segment *seg = first_seg(lv);
|
||||||
|
|
||||||
|
if (seg_is_striped(seg))
|
||||||
|
return striped_LVT;
|
||||||
|
if (seg_is_linear(seg))
|
||||||
|
return linear_LVT;
|
||||||
|
if (lv_is_cow(lv))
|
||||||
|
return snapshot_LVT;
|
||||||
|
if (lv_is_thin_volume(lv))
|
||||||
|
return thin_LVT;
|
||||||
|
if (lv_is_thin_pool(lv))
|
||||||
|
return thinpool_LVT;
|
||||||
|
if (lv_is_cache(lv))
|
||||||
|
return cache_LVT;
|
||||||
|
if (lv_is_cache_pool(lv))
|
||||||
|
return cachepool_LVT;
|
||||||
|
if (lv_is_mirror(lv))
|
||||||
|
return mirror_LVT;
|
||||||
|
if (lv_is_raid(lv))
|
||||||
|
return raid_LVT;
|
||||||
|
if (seg_is_raid0(seg))
|
||||||
|
return raid0_LVT;
|
||||||
|
if (seg_is_raid1(seg))
|
||||||
|
return raid1_LVT;
|
||||||
|
if (seg_is_raid4(seg))
|
||||||
|
return raid4_LVT;
|
||||||
|
#if 0
|
||||||
|
if (seg_is_raid5(seg))
|
||||||
|
return raid5_LVT;
|
||||||
|
if (seg_is_raid6(seg))
|
||||||
|
return raid6_LVT;
|
||||||
|
#endif
|
||||||
|
if (seg_is_raid10(seg))
|
||||||
|
return raid10_LVT;
|
||||||
|
|
||||||
|
log_error(INTERNAL_ERROR "unknown lv type for %s", display_lvname(lv));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call lv_is_<type> for each <type>_LVT bit set in lvt_bits.
|
||||||
|
* If lv matches one of the specified lv types, then return 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int _lv_types_match(struct cmd_context *cmd, struct logical_volume *lv, uint64_t lvt_bits,
|
||||||
|
uint64_t *match_bits, uint64_t *unmatch_bits)
|
||||||
|
{
|
||||||
|
struct lv_types *type;
|
||||||
|
int lvt_enum;
|
||||||
|
int found_a_match = 0;
|
||||||
|
int match;
|
||||||
|
|
||||||
|
if (match_bits)
|
||||||
|
*match_bits = 0;
|
||||||
|
if (unmatch_bits)
|
||||||
|
*unmatch_bits = 0;
|
||||||
|
|
||||||
|
for (lvt_enum = 1; lvt_enum < LVT_COUNT; lvt_enum++) {
|
||||||
|
if (!lvt_bit_is_set(lvt_bits, lvt_enum))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!(type = get_lv_type(lvt_enum)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* All types are currently handled by _lv_is_type()
|
||||||
|
* because lv_is_type() are #defines and not exposed
|
||||||
|
* in tools.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!type->fn)
|
||||||
|
match = _lv_is_type(cmd, lv, lvt_enum);
|
||||||
|
else
|
||||||
|
match = type->fn(cmd, lv);
|
||||||
|
|
||||||
|
if (match)
|
||||||
|
found_a_match = 1;
|
||||||
|
|
||||||
|
if (match_bits && match)
|
||||||
|
*match_bits |= lvt_enum_to_bit(lvt_enum);
|
||||||
|
|
||||||
|
if (unmatch_bits && !match)
|
||||||
|
*unmatch_bits |= lvt_enum_to_bit(lvt_enum);
|
||||||
|
}
|
||||||
|
|
||||||
|
return found_a_match;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call lv_is_<prop> for each <prop>_LVP bit set in lvp_bits.
|
||||||
|
* If lv matches all of the specified lv properties, then return 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int _lv_props_match(struct cmd_context *cmd, struct logical_volume *lv, uint64_t lvp_bits,
|
||||||
|
uint64_t *match_bits, uint64_t *unmatch_bits)
|
||||||
|
{
|
||||||
|
struct lv_props *prop;
|
||||||
|
int lvp_enum;
|
||||||
|
int found_a_mismatch = 0;
|
||||||
|
int match;
|
||||||
|
|
||||||
|
if (match_bits)
|
||||||
|
*match_bits = 0;
|
||||||
|
if (unmatch_bits)
|
||||||
|
*unmatch_bits = 0;
|
||||||
|
|
||||||
|
for (lvp_enum = 1; lvp_enum < LVP_COUNT; lvp_enum++) {
|
||||||
|
if (!lvp_bit_is_set(lvp_bits, lvp_enum))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!(prop = get_lv_prop(lvp_enum)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!prop->fn)
|
||||||
|
match = _lv_is_prop(cmd, lv, lvp_enum);
|
||||||
|
else
|
||||||
|
match = prop->fn(cmd, lv);
|
||||||
|
|
||||||
|
if (!match)
|
||||||
|
found_a_mismatch = 1;
|
||||||
|
|
||||||
|
if (match_bits && match)
|
||||||
|
*match_bits |= lvp_enum_to_bit(lvp_enum);
|
||||||
|
|
||||||
|
if (unmatch_bits && !match)
|
||||||
|
*unmatch_bits |= lvp_enum_to_bit(lvp_enum);
|
||||||
|
}
|
||||||
|
|
||||||
|
return !found_a_mismatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the command definition specifies one required positional
|
||||||
|
* LV (possibly repeatable), and specifies accepted LV types,
|
||||||
|
* then verify that the LV being processed matches one of those
|
||||||
|
* types.
|
||||||
|
*
|
||||||
|
* process_each_lv() can only be used for commands that have
|
||||||
|
* one positional LV arg (optionally repeating, where each is
|
||||||
|
* processed independently.) It cannot work for commands that
|
||||||
|
* have different required LVs in designated positions, like
|
||||||
|
* 'lvrename LV1 LV2', where each LV is not processed
|
||||||
|
* independently. That means that this LV type check only
|
||||||
|
* needs to check the lv_type of the first positional arg.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int _check_lv_types(struct cmd_context *cmd, struct logical_volume *lv)
|
||||||
|
{
|
||||||
|
int ret = 1;
|
||||||
|
|
||||||
|
if ((cmd->command->rp_count == 1) &&
|
||||||
|
val_bit_is_set(cmd->command->required_pos_args[0].def.val_bits, lv_VAL) &&
|
||||||
|
cmd->command->required_pos_args[0].def.lvt_bits) {
|
||||||
|
ret = _lv_types_match(cmd, lv, cmd->command->required_pos_args[0].def.lvt_bits, NULL, NULL);
|
||||||
|
if (!ret) {
|
||||||
|
int lvt_enum = _get_lvt_enum(lv);
|
||||||
|
struct lv_types *type = get_lv_type(lvt_enum);
|
||||||
|
log_warn("Operation on LV %s which has invalid type %s.",
|
||||||
|
display_lvname(lv), type ? type->name : "unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if LV passes each rule specified in command definition. */
|
||||||
|
|
||||||
|
static int _check_lv_rules(struct cmd_context *cmd, struct logical_volume *lv)
|
||||||
|
{
|
||||||
|
char buf[64];
|
||||||
|
struct cmd_rule *rule;
|
||||||
|
struct lv_types *lvtype = NULL;
|
||||||
|
uint64_t lv_props_match_bits, lv_props_unmatch_bits;
|
||||||
|
uint64_t lv_types_match_bits, lv_types_unmatch_bits;
|
||||||
|
int opts_match_count, opts_unmatch_count;
|
||||||
|
int lvt_enum;
|
||||||
|
int ret = 1;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
lvt_enum = _get_lvt_enum(lv);
|
||||||
|
if (lvt_enum)
|
||||||
|
lvtype = get_lv_type(lvt_enum);
|
||||||
|
|
||||||
|
for (i = 0; i < cmd->command->rule_count; i++) {
|
||||||
|
rule = &cmd->command->rules[i];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RULE: <conditions> INVALID|REQUIRE <checks>
|
||||||
|
*
|
||||||
|
* If all the conditions apply to the command+LV, then
|
||||||
|
* the checks are performed. If all conditions are zero
|
||||||
|
* (!opts_count, !lvt_bits, !lvp_bits), then the check
|
||||||
|
* is always performed.
|
||||||
|
*
|
||||||
|
* Conditions:
|
||||||
|
*
|
||||||
|
* 1. options (opts): if any of the specified options are set,
|
||||||
|
* then the checks may apply.
|
||||||
|
*
|
||||||
|
* 2. LV types (lvt_bits): if any of the specified LV types
|
||||||
|
* match the LV, then the checks may apply.
|
||||||
|
*
|
||||||
|
* 3. LV properties (lvp_bits): if all of the specified
|
||||||
|
* LV properties match the LV, then the checks may apply.
|
||||||
|
*
|
||||||
|
* If conditions 1, 2, 3 all pass, then the checks apply.
|
||||||
|
*
|
||||||
|
* Checks:
|
||||||
|
*
|
||||||
|
* 1. options (check_opts):
|
||||||
|
* INVALID: if any of the specified options are set,
|
||||||
|
* then the command fails.
|
||||||
|
* REQUIRE: if any of the specified options are not set,
|
||||||
|
* then the command fails.
|
||||||
|
*
|
||||||
|
* 2. LV types (check_lvt_bits):
|
||||||
|
* INVALID: if any of the specified LV types match the LV,
|
||||||
|
* then the command fails.
|
||||||
|
* REQUIRE: if none of the specified LV types match the LV,
|
||||||
|
* then the command fails.
|
||||||
|
*
|
||||||
|
* 3. LV properties (check_lvp_bits):
|
||||||
|
* INVALID: if any of the specified LV properties match
|
||||||
|
* the LV, then the command fails.
|
||||||
|
* REQUIRE: if any of the specified LV properties do not match
|
||||||
|
* the LV, then the command fails.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (rule->opts_count && !opt_in_list_is_set(cmd, rule->opts, rule->opts_count, NULL, NULL))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* If LV matches one type in lvt_bits, this returns 1. */
|
||||||
|
if (rule->lvt_bits && !_lv_types_match(cmd, lv, rule->lvt_bits, NULL, NULL))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* If LV matches all properties in lvp_bits, this returns 1. */
|
||||||
|
if (rule->lvp_bits && !_lv_props_match(cmd, lv, rule->lvp_bits, NULL, NULL))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check the options, LV types, LV properties.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (rule->check_opts)
|
||||||
|
opt_in_list_is_set(cmd, rule->check_opts, rule->check_opts_count,
|
||||||
|
&opts_match_count, &opts_unmatch_count);
|
||||||
|
|
||||||
|
if (rule->check_lvt_bits)
|
||||||
|
_lv_types_match(cmd, lv, rule->check_lvt_bits,
|
||||||
|
&lv_types_match_bits, &lv_types_unmatch_bits);
|
||||||
|
|
||||||
|
if (rule->check_lvp_bits)
|
||||||
|
_lv_props_match(cmd, lv, rule->check_lvp_bits,
|
||||||
|
&lv_props_match_bits, &lv_props_unmatch_bits);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Evaluate if the check results pass based on the rule.
|
||||||
|
* The options are checked again here because the previous
|
||||||
|
* option validation (during command matching) does not cover
|
||||||
|
* cases where the option is combined with conditions of LV types
|
||||||
|
* or properties.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Fail if any invalid options are set. */
|
||||||
|
|
||||||
|
if (rule->check_opts && (rule->rule == RULE_INVALID) && opts_match_count) {
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
opt_array_to_str(cmd, rule->check_opts, rule->check_opts_count, buf, sizeof(buf));
|
||||||
|
log_warn("An invalid option is set: %s", buf);
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fail if any required options are not set. */
|
||||||
|
|
||||||
|
if (rule->check_opts && (rule->rule == RULE_REQUIRE) && opts_unmatch_count) {
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
opt_array_to_str(cmd, rule->check_opts, rule->check_opts_count, buf, sizeof(buf));
|
||||||
|
log_warn("A required option is not set: %s", buf);
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fail if the LV matches any of the invalid LV types. */
|
||||||
|
|
||||||
|
if (rule->check_lvt_bits && (rule->rule == RULE_INVALID) && lv_types_match_bits) {
|
||||||
|
log_warn("Command on LV %s with invalid type: %s",
|
||||||
|
display_lvname(lv), lvtype ? lvtype->name : "unknown");
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fail if the LV does not match any of the required LV types. */
|
||||||
|
|
||||||
|
if (rule->check_lvt_bits && (rule->rule == RULE_REQUIRE) && !lv_types_match_bits) {
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
lvt_bits_to_str(rule->check_lvt_bits, buf, sizeof(buf));
|
||||||
|
log_warn("Command on LV %s with type %s does not match required type: %s",
|
||||||
|
display_lvname(lv), lvtype ? lvtype->name : "unknown", buf);
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fail if the LV matches any of the invalid LV properties. */
|
||||||
|
|
||||||
|
if (rule->check_lvp_bits && (rule->rule == RULE_INVALID) && lv_props_match_bits) {
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
lvp_bits_to_str(lv_props_match_bits, buf, sizeof(buf));
|
||||||
|
log_warn("Command on LV %s with invalid properties: %s",
|
||||||
|
display_lvname(lv), buf);
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fail if the LV does not match any of the required LV properties. */
|
||||||
|
|
||||||
|
if (rule->check_lvp_bits && (rule->rule == RULE_REQUIRE) && lv_props_unmatch_bits) {
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
lvp_bits_to_str(lv_props_unmatch_bits, buf, sizeof(buf));
|
||||||
|
log_warn("Command on LV %s requires properties: %s",
|
||||||
|
display_lvname(lv), buf);
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||||
struct dm_list *arg_lvnames, const struct dm_list *tags_in,
|
struct dm_list *arg_lvnames, const struct dm_list *tags_in,
|
||||||
int stop_on_error,
|
int stop_on_error,
|
||||||
@@ -2350,9 +2885,6 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
|||||||
struct dm_list found_arg_lvnames;
|
struct dm_list found_arg_lvnames;
|
||||||
struct glv_list *glvl, *tglvl;
|
struct glv_list *glvl, *tglvl;
|
||||||
int do_report_ret_code = 1;
|
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);
|
log_set_report_object_type(LOG_REPORT_OBJECT_TYPE_LV);
|
||||||
|
|
||||||
@@ -2504,65 +3036,42 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the command definition specifies one required positional
|
* The command definition may include restrictions on the
|
||||||
* LV (possibly repeatable), and specifies accepted LV types,
|
* types and properties of LVs that can be processed.
|
||||||
* 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) &&
|
if (!_check_lv_types(cmd, lvl->lv)) {
|
||||||
val_bit_is_set(cmd->command->required_pos_args[0].def.val_bits, lv_VAL) &&
|
/* FIXME: include this result in report log? */
|
||||||
cmd->command->required_pos_args[0].def.lv_types) {
|
/* FIXME: avoid duplicating message for each level */
|
||||||
|
|
||||||
lv_types = cmd->command->required_pos_args[0].def.lv_types;
|
if (str_list_match_item(&found_arg_lvnames, lvl->lv->name)) {
|
||||||
lv = lvl->lv;
|
log_error("Operation not permitted (%s %d) on LV %s.",
|
||||||
seg = first_seg(lv);
|
cmd->command->command_line_id, cmd->command->command_line_enum,
|
||||||
|
display_lvname(lvl->lv));
|
||||||
if ((lv_is_cow(lv) && !(lv_types & ARG_DEF_LV_SNAPSHOT)) ||
|
ret_max = ECMD_FAILED;
|
||||||
(lv_is_thin_volume(lv) && !(lv_types & ARG_DEF_LV_THIN)) ||
|
} else {
|
||||||
(lv_is_thin_pool(lv) && !(lv_types & ARG_DEF_LV_THINPOOL)) ||
|
log_warn("Operation not permitted (%s %d) on LV %s.",
|
||||||
(lv_is_cache(lv) && !(lv_types & ARG_DEF_LV_CACHE)) ||
|
cmd->command->command_line_id, cmd->command->command_line_enum,
|
||||||
(lv_is_cache_pool(lv) && !(lv_types & ARG_DEF_LV_CACHEPOOL)) ||
|
display_lvname(lvl->lv));
|
||||||
(lv_is_mirror(lv) && !(lv_types & ARG_DEF_LV_MIRROR)) ||
|
|
||||||
(lv_is_raid(lv) && !(lv_types & (ARG_DEF_LV_RAID | ARG_DEF_LV_RAID0 | ARG_DEF_LV_RAID1 | ARG_DEF_LV_RAID4 | ARG_DEF_LV_RAID5 | ARG_DEF_LV_RAID6 | ARG_DEF_LV_RAID10))) ||
|
|
||||||
(segtype_is_striped(seg->segtype) && !(lv_types & ARG_DEF_LV_STRIPED)) ||
|
|
||||||
(segtype_is_linear(seg->segtype) && !(lv_types & ARG_DEF_LV_LINEAR))) {
|
|
||||||
/*
|
|
||||||
* If a named LV arg cannot be processed it's an error, otherwise
|
|
||||||
* the LV is skipped and doesn't cause the command to fail.
|
|
||||||
*/
|
|
||||||
if (str_list_match_item(&found_arg_lvnames, lv->name)) {
|
|
||||||
log_error("Operation not permitted (%s %d) on LV %s with type %s.",
|
|
||||||
cmd->command->command_line_id, cmd->command->command_line_enum,
|
|
||||||
display_lvname(lv), seg->segtype->name);
|
|
||||||
ret_max = ECMD_FAILED;
|
|
||||||
} else {
|
|
||||||
log_warn("Operation not permitted (%s %d) on LV %s with type %s.",
|
|
||||||
cmd->command->command_line_id, cmd->command->command_line_enum,
|
|
||||||
display_lvname(lv), seg->segtype->name);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_check_lv_rules(cmd, lvl->lv)) {
|
||||||
|
/* FIXME: include this result in report log? */
|
||||||
|
/* FIXME: avoid duplicating message for each level */
|
||||||
|
|
||||||
|
if (str_list_match_item(&found_arg_lvnames, lvl->lv->name)) {
|
||||||
|
log_error("Operation not permitted (%s %d) on LV %s.",
|
||||||
|
cmd->command->command_line_id, cmd->command->command_line_enum,
|
||||||
|
display_lvname(lvl->lv));
|
||||||
|
ret_max = ECMD_FAILED;
|
||||||
|
} else {
|
||||||
|
log_warn("Operation not permitted (%s %d) on LV %s.",
|
||||||
|
cmd->command->command_line_id, cmd->command->command_line_enum,
|
||||||
|
display_lvname(lvl->lv));
|
||||||
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_very_verbose("Processing LV %s in VG %s.", lvl->lv->name, vg->name);
|
log_very_verbose("Processing LV %s in VG %s.", lvl->lv->name, vg->name);
|
||||||
|
@@ -159,6 +159,12 @@ const char *extract_vgname(struct cmd_context *cmd, const char *lv_name);
|
|||||||
const char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name,
|
const char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name,
|
||||||
unsigned *dev_dir_found);
|
unsigned *dev_dir_found);
|
||||||
|
|
||||||
|
int opt_in_list_is_set(struct cmd_context *cmd, int *opts, int count,
|
||||||
|
int *match_count, int *unmatch_count);
|
||||||
|
|
||||||
|
void opt_array_to_str(struct cmd_context *cmd, int *opts, int count,
|
||||||
|
char *buf, int len);
|
||||||
|
|
||||||
int pvcreate_params_from_args(struct cmd_context *cmd, struct pvcreate_params *pp);
|
int pvcreate_params_from_args(struct cmd_context *cmd, struct pvcreate_params *pp);
|
||||||
int pvcreate_each_device(struct cmd_context *cmd, struct processing_handle *handle, struct pvcreate_params *pp);
|
int pvcreate_each_device(struct cmd_context *cmd, struct processing_handle *handle, struct pvcreate_params *pp);
|
||||||
|
|
||||||
|
@@ -50,14 +50,14 @@
|
|||||||
#define CMD_LEN 256
|
#define CMD_LEN 256
|
||||||
#define MAX_ARGS 64
|
#define MAX_ARGS 64
|
||||||
|
|
||||||
/* define the enums for the values accepted by command line --options */
|
/* define the enums for the values accepted by command line --options, foo_VAL */
|
||||||
enum {
|
enum {
|
||||||
#define val(a, b, c, d) a ,
|
#define val(a, b, c, d) a ,
|
||||||
#include "vals.h"
|
#include "vals.h"
|
||||||
#undef val
|
#undef val
|
||||||
};
|
};
|
||||||
|
|
||||||
/* define the enums for the command line --options */
|
/* define the enums for the command line --options, foo_ARG */
|
||||||
enum {
|
enum {
|
||||||
#define arg(a, b, c, d, e, f) a ,
|
#define arg(a, b, c, d, e, f) a ,
|
||||||
#include "args.h"
|
#include "args.h"
|
||||||
@@ -69,6 +69,20 @@ enum {
|
|||||||
#include "commands.h"
|
#include "commands.h"
|
||||||
#undef xx
|
#undef xx
|
||||||
|
|
||||||
|
/* define enums for LV properties, foo_LVP */
|
||||||
|
enum {
|
||||||
|
#define lvp(a, b, c) a ,
|
||||||
|
#include "lv_props.h"
|
||||||
|
#undef lvp
|
||||||
|
};
|
||||||
|
|
||||||
|
/* define enums for LV types, foo_LVT */
|
||||||
|
enum {
|
||||||
|
#define lvt(a, b, c) a ,
|
||||||
|
#include "lv_types.h"
|
||||||
|
#undef lvt
|
||||||
|
};
|
||||||
|
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
|
|
||||||
#define ARG_COUNTABLE 0x00000001 /* E.g. -vvvv */
|
#define ARG_COUNTABLE 0x00000001 /* E.g. -vvvv */
|
||||||
@@ -111,6 +125,21 @@ struct val_props {
|
|||||||
const char *usage;
|
const char *usage;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* a global table of possible LV properties */
|
||||||
|
struct lv_props {
|
||||||
|
int lvp_enum; /* is_foo_LVP from lv_props.h */
|
||||||
|
const char *name; /* "lv_is_foo" used in command-lines.in */
|
||||||
|
int (*fn) (struct cmd_context *cmd, struct logical_volume *lv); /* lv_is_foo() */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* a global table of possible LV types */
|
||||||
|
/* (as exposed externally in command line interface, not exactly as internal segtype is used) */
|
||||||
|
struct lv_types {
|
||||||
|
int lvt_enum; /* is_foo_LVT from lv_types.h */
|
||||||
|
const char *name; /* "foo" used in command-lines.in, i.e. LV_foo */
|
||||||
|
int (*fn) (struct cmd_context *cmd, struct logical_volume *lv); /* lv_is_foo() */
|
||||||
|
};
|
||||||
|
|
||||||
#define CACHE_VGMETADATA 0x00000001
|
#define CACHE_VGMETADATA 0x00000001
|
||||||
#define PERMITTED_READ_ONLY 0x00000002
|
#define PERMITTED_READ_ONLY 0x00000002
|
||||||
/* Process all VGs if none specified on the command line. */
|
/* Process all VGs if none specified on the command line. */
|
||||||
@@ -209,4 +238,23 @@ int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg,
|
|||||||
|
|
||||||
int vgchange_background_polling(struct cmd_context *cmd, struct volume_group *vg);
|
int vgchange_background_polling(struct cmd_context *cmd, struct volume_group *vg);
|
||||||
|
|
||||||
|
struct lv_props *get_lv_prop(int lvp_enum);
|
||||||
|
struct lv_types *get_lv_type(int lvt_enum);
|
||||||
|
|
||||||
|
int lvchange_properties_cmd(struct cmd_context *cmd, int argc, char **argv);
|
||||||
|
int lvchange_activate_cmd(struct cmd_context *cmd, int argc, char **argv);
|
||||||
|
int lvchange_refresh_cmd(struct cmd_context *cmd, int argc, char **argv);
|
||||||
|
int lvchange_resync_cmd(struct cmd_context *cmd, int argc, char **argv);
|
||||||
|
int lvchange_syncaction_cmd(struct cmd_context *cmd, int argc, char **argv);
|
||||||
|
int lvchange_rebuild_cmd(struct cmd_context *cmd, int argc, char **argv);
|
||||||
|
int lvchange_monitor_poll_cmd(struct cmd_context *cmd, int argc, char **argv);
|
||||||
|
int lvchange_persistent_cmd(struct cmd_context *cmd, int argc, char **argv);
|
||||||
|
|
||||||
|
int lvconvert_repair_pvs_or_thinpool_cmd(struct cmd_context *cmd, int argc, char **argv);
|
||||||
|
int lvconvert_replace_pv_cmd(struct cmd_context *cmd, int argc, char **argv);
|
||||||
|
|
||||||
|
int lvconvert_merge_snapshot_cmd(struct cmd_context *cmd, int argc, char **argv);
|
||||||
|
int lvconvert_split_snapshot_cmd(struct cmd_context *cmd, int argc, char **argv);
|
||||||
|
int lvconvert_combine_split_snapshot_cmd(struct cmd_context *cmd, int argc, char **argv);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -113,7 +113,7 @@ val(mirrorlog_VAL, mirrorlog_arg, "MirrorLog", "core|disk")
|
|||||||
val(sizekb_VAL, size_kb_arg, "SizeKB", "Number[k|unit]")
|
val(sizekb_VAL, size_kb_arg, "SizeKB", "Number[k|unit]")
|
||||||
val(sizemb_VAL, size_mb_arg, "SizeMB", "Number[m|unit]")
|
val(sizemb_VAL, size_mb_arg, "SizeMB", "Number[m|unit]")
|
||||||
val(numsigned_VAL, int_arg_with_sign, "SNumber", "[+|-]Number")
|
val(numsigned_VAL, int_arg_with_sign, "SNumber", "[+|-]Number")
|
||||||
val(numsignedper_VAL, int_arg_with_sign_and_percent, "SNumberP", "[+|-]Number[%{VG|PVS|FREE}]")
|
val(numsignedper_VAL, int_arg_with_sign_and_percent, "SNumberP", "[+|-]Number[%VG|%PVS|%FREE]")
|
||||||
val(permission_VAL, permission_arg, "Permission", "rw|r")
|
val(permission_VAL, permission_arg, "Permission", "rw|r")
|
||||||
val(metadatatype_VAL, metadatatype_arg, "MetadataType", "lvm2|lvm1")
|
val(metadatatype_VAL, metadatatype_arg, "MetadataType", "lvm2|lvm1")
|
||||||
val(units_VAL, string_arg, "Units", "hHbBsSkKmMgGtTpPeE")
|
val(units_VAL, string_arg, "Units", "hHbBsSkKmMgGtTpPeE")
|
||||||
|
Reference in New Issue
Block a user