mirror of
git://sourceware.org/git/lvm2.git
synced 2025-09-27 05:44:18 +03:00
Compare commits
39 Commits
dev-dct-cm
...
v2_02_167
Author | SHA1 | Date | |
---|---|---|---|
|
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.136-git (2016-11-05)
|
||||
|
10
WHATS_NEW
10
WHATS_NEW
@@ -1,5 +1,11 @@
|
||||
Version 2.02.167 -
|
||||
======================================
|
||||
Version 2.02.167 - 5th November 2016
|
||||
====================================
|
||||
Use log_error in regex and sysfs filter to describe reason of failure.
|
||||
Fix blkdeactivate to deactivate dev stack if dev on top already unmounted.
|
||||
Prevent non-synced raid1 repair unless --force
|
||||
Prevent raid4 creation/conversion on non-supporting kernels
|
||||
Add direct striped -> raid4 conversion
|
||||
Fix raid4 parity image pair position on conversions from striped/raid0*
|
||||
Fix a few unconverted return code values for some lvconvert error path.
|
||||
Disable lvconvert of thin pool to raid while active.
|
||||
Disable systemd service start rate limiting for lvm2-pvscan@.service.
|
||||
|
12
WHATS_NEW_DM
12
WHATS_NEW_DM
@@ -1,5 +1,13 @@
|
||||
Version 1.02.136 -
|
||||
======================================
|
||||
Version 1.02.136 - 5th November 2016
|
||||
====================================
|
||||
Log failure of raid device with log_error level.
|
||||
Use dm_log_with_errno and translate runtime to dm_log only when needed.
|
||||
Make log messages from dm and lvm library different from dmeventd.
|
||||
Notice and Info messages are again logged from dmeventd and its plugins.
|
||||
Dmeventd now also respects DM_ABORT_ON_INTERNAL_ERRORS as libdm based tool.
|
||||
Report as non default dm logging also when logging with errno was changed.
|
||||
Use log_level() macro to consistently decode message log level in dmeventd.
|
||||
Still produce output when dmsetup dependency tree building finds dev missing.
|
||||
Check and report pthread_sigmask() failure in dmeventd.
|
||||
Check mem alloc fail in _canonicalize_field_ids().
|
||||
Use unsigned math when checking more then 31 legs of raid.
|
||||
|
@@ -99,13 +99,28 @@ static time_t _idle_since = 0;
|
||||
static char **_initial_registrations = 0;
|
||||
|
||||
/* FIXME Make configurable at runtime */
|
||||
__attribute__((format(printf, 4, 5)))
|
||||
static void _dmeventd_log(int level, const char *file, int line,
|
||||
const char *format, ...)
|
||||
|
||||
/* All libdm messages */
|
||||
__attribute__((format(printf, 5, 6)))
|
||||
static void _libdm_log(int level, const char *file, int line,
|
||||
int dm_errno_or_class, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
dm_event_log("dm", level, file, line, 0, format, ap);
|
||||
dm_event_log("#dm", level, file, line, dm_errno_or_class, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/* All dmeventd messages */
|
||||
#undef LOG_MESG
|
||||
#define LOG_MESG(l, f, ln, e, x...) _dmeventd_log(l, f, ln, e, ## x)
|
||||
__attribute__((format(printf, 5, 6)))
|
||||
static void _dmeventd_log(int level, const char *file, int line,
|
||||
int dm_errno_or_class, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
dm_event_log("dmeventd", level, file, line, dm_errno_or_class, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
@@ -2191,7 +2206,7 @@ int main(int argc, char *argv[])
|
||||
openlog("dmeventd", LOG_PID, LOG_DAEMON);
|
||||
|
||||
dm_event_log_set(_debug_level, _use_syslog);
|
||||
dm_log_init(_dmeventd_log);
|
||||
dm_log_with_errno_init(_libdm_log);
|
||||
|
||||
(void) dm_prepare_selinux_context(DMEVENTD_PIDFILE, S_IFREG);
|
||||
if (dm_create_lockfile(DMEVENTD_PIDFILE) == 0)
|
||||
|
@@ -865,28 +865,38 @@ void dm_event_log(const char *subsys, int level, const char *file,
|
||||
int line, int dm_errno_or_class,
|
||||
const char *format, va_list ap)
|
||||
{
|
||||
static int _abort_on_internal_errors = -1;
|
||||
static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static time_t start = 0;
|
||||
const char *indent = "";
|
||||
FILE *stream = stdout;
|
||||
FILE *stream = log_stderr(level) ? stderr : stdout;
|
||||
int prio;
|
||||
time_t now;
|
||||
int log_with_debug = 0;
|
||||
|
||||
switch (level & ~(_LOG_STDERR | _LOG_ONCE)) {
|
||||
if (subsys[0] == '#') {
|
||||
/* Subsystems starting with '#' are logged
|
||||
* only when debugging is enabled. */
|
||||
log_with_debug++;
|
||||
subsys++;
|
||||
}
|
||||
|
||||
switch (log_level(level)) {
|
||||
case _LOG_DEBUG:
|
||||
/* Never shown without -ddd */
|
||||
if (_debug_level < 3)
|
||||
return;
|
||||
prio = LOG_DEBUG;
|
||||
indent = " ";
|
||||
break;
|
||||
case _LOG_INFO:
|
||||
if (_debug_level < 2)
|
||||
if (log_with_debug && _debug_level < 2)
|
||||
return;
|
||||
prio = LOG_INFO;
|
||||
indent = " ";
|
||||
break;
|
||||
case _LOG_NOTICE:
|
||||
if (_debug_level < 1)
|
||||
if (log_with_debug && _debug_level < 1)
|
||||
return;
|
||||
prio = LOG_NOTICE;
|
||||
indent = " ";
|
||||
@@ -912,12 +922,13 @@ void dm_event_log(const char *subsys, int level, const char *file,
|
||||
if (!start)
|
||||
start = now;
|
||||
now -= start;
|
||||
fprintf(stream, "[%2d:%02d] %8x:%-6s%s",
|
||||
(int)now / 60, (int)now % 60,
|
||||
// TODO: Maybe use shorter ID
|
||||
// ((int)(pthread_self()) >> 6) & 0xffff,
|
||||
(int)pthread_self(), subsys,
|
||||
(_debug_level > 3) ? "" : indent);
|
||||
if (_debug_level)
|
||||
fprintf(stream, "[%2d:%02d] %8x:%-6s%s",
|
||||
(int)now / 60, (int)now % 60,
|
||||
// TODO: Maybe use shorter ID
|
||||
// ((int)(pthread_self()) >> 6) & 0xffff,
|
||||
(int)pthread_self(), subsys,
|
||||
(_debug_level > 3) ? "" : indent);
|
||||
if (_debug_level > 3)
|
||||
fprintf(stream, "%28s:%4d %s", file, line, indent);
|
||||
vfprintf(stream, _(format), ap);
|
||||
@@ -926,6 +937,15 @@ void dm_event_log(const char *subsys, int level, const char *file,
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_log_mutex);
|
||||
|
||||
if (_abort_on_internal_errors < 0)
|
||||
/* Set when env DM_ABORT_ON_INTERNAL_ERRORS is not "0" */
|
||||
_abort_on_internal_errors =
|
||||
strcmp(getenv("DM_ABORT_ON_INTERNAL_ERRORS") ? : "0", "0");
|
||||
|
||||
if (_abort_on_internal_errors &&
|
||||
!strncmp(format, INTERNAL_ERROR, sizeof(INTERNAL_ERROR) - 1))
|
||||
abort();
|
||||
}
|
||||
|
||||
#if 0 /* left out for now */
|
||||
|
@@ -32,7 +32,7 @@ static int _register_count = 0;
|
||||
static struct dm_pool *_mem_pool = NULL;
|
||||
static void *_lvm_handle = NULL;
|
||||
|
||||
DM_EVENT_LOG_FN("lvm")
|
||||
DM_EVENT_LOG_FN("#lvm")
|
||||
|
||||
static void _lvm2_print_log(int level, const char *file, int line,
|
||||
int dm_errno_or_class, const char *msg)
|
||||
|
@@ -73,8 +73,10 @@ static int _get_mirror_event(struct dso_state *state, char *params)
|
||||
unsigned i;
|
||||
struct dm_status_mirror *ms;
|
||||
|
||||
if (!dm_get_status_mirror(state->mem, params, &ms))
|
||||
goto_out;
|
||||
if (!dm_get_status_mirror(state->mem, params, &ms)) {
|
||||
log_error("Unable to parse mirror status string.");
|
||||
return ME_IGNORE;
|
||||
}
|
||||
|
||||
/* Check for bad mirror devices */
|
||||
for (i = 0; i < ms->dev_count; ++i)
|
||||
@@ -95,27 +97,23 @@ static int _get_mirror_event(struct dso_state *state, char *params)
|
||||
dm_pool_free(state->mem, ms);
|
||||
|
||||
return r;
|
||||
|
||||
out:
|
||||
log_error("Unable to parse mirror status string.");
|
||||
|
||||
return ME_IGNORE;
|
||||
}
|
||||
|
||||
static int _remove_failed_devices(const char *cmd_lvscan, const char *cmd_lvconvert)
|
||||
static int _remove_failed_devices(const char *cmd_lvscan, const char *cmd_lvconvert,
|
||||
const char *device)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!dmeventd_lvm2_run_with_lock(cmd_lvscan))
|
||||
log_info("Re-scan of mirrored device failed.");
|
||||
log_warn("WARNING: Re-scan of mirrored device %s failed.", device);
|
||||
|
||||
/* if repair goes OK, report success even if lvscan has failed */
|
||||
r = dmeventd_lvm2_run_with_lock(cmd_lvconvert);
|
||||
if (!dmeventd_lvm2_run_with_lock(cmd_lvconvert)) {
|
||||
log_error("Repair of mirrored device %s failed.", device);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_info("Repair of mirrored device %s.",
|
||||
(r) ? "finished successfully" : "failed");
|
||||
log_info("Repair of mirrored device %s finished successfully.", device);
|
||||
|
||||
return r;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void process_event(struct dm_task *dmt,
|
||||
@@ -154,7 +152,8 @@ void process_event(struct dm_task *dmt,
|
||||
case ME_FAILURE:
|
||||
log_error("Device failure in %s.", device);
|
||||
if (!_remove_failed_devices(state->cmd_lvscan,
|
||||
state->cmd_lvconvert))
|
||||
state->cmd_lvconvert,
|
||||
device))
|
||||
/* FIXME Why are all the error return codes unused? Get rid of them? */
|
||||
log_error("Failed to remove faulty devices in %s.",
|
||||
device);
|
||||
@@ -168,7 +167,7 @@ void process_event(struct dm_task *dmt,
|
||||
break;
|
||||
default:
|
||||
/* FIXME Provide value then! */
|
||||
log_info("Unknown event received.");
|
||||
log_warn("WARNING: %s received unknown event.", device);
|
||||
}
|
||||
} while (next);
|
||||
}
|
||||
|
@@ -76,7 +76,7 @@ static int _process_raid_event(struct dso_state *state, char *params, const char
|
||||
|
||||
/* if repair goes OK, report success even if lvscan has failed */
|
||||
if (!dmeventd_lvm2_run_with_lock(state->cmd_lvconvert)) {
|
||||
log_info("Repair of RAID device %s failed.", device);
|
||||
log_error("Repair of RAID device %s failed.", device);
|
||||
r = 0;
|
||||
}
|
||||
} else {
|
||||
|
@@ -301,7 +301,7 @@ out:
|
||||
static int _use_policy(struct dm_task *dmt, struct dso_state *state)
|
||||
{
|
||||
#if THIN_DEBUG
|
||||
log_info("dmeventd executes: %s.", state->cmd_str);
|
||||
log_debug("dmeventd executes: %s.", state->cmd_str);
|
||||
#endif
|
||||
if (!dmeventd_lvm2_run_with_lock(state->cmd_str)) {
|
||||
log_error("Failed to extend thin pool %s.",
|
||||
|
@@ -7,19 +7,13 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import threading
|
||||
import subprocess
|
||||
from . import cfg
|
||||
import time
|
||||
from .cmdhandler import options_to_cli_args
|
||||
import dbus
|
||||
from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug
|
||||
import traceback
|
||||
import os
|
||||
|
||||
_rlock = threading.RLock()
|
||||
_thread_list = list()
|
||||
|
||||
|
||||
def pv_move_lv_cmd(move_options, lv_full_name,
|
||||
pv_source, pv_source_range, pv_dest_range_list):
|
||||
@@ -42,15 +36,40 @@ def lv_merge_cmd(merge_options, lv_full_name):
|
||||
return cmd
|
||||
|
||||
|
||||
def _move_merge(interface_name, cmd, job_state):
|
||||
add(cmd, job_state)
|
||||
def _move_merge(interface_name, command, job_state):
|
||||
# We need to execute these command stand alone by forking & exec'ing
|
||||
# the command always as we will be getting periodic output from them on
|
||||
# the status of the long running operation.
|
||||
command.insert(0, cfg.LVM_CMD)
|
||||
process = subprocess.Popen(command, stdout=subprocess.PIPE,
|
||||
env=os.environ,
|
||||
stderr=subprocess.PIPE, close_fds=True)
|
||||
|
||||
done = job_state.Wait(-1)
|
||||
if not done:
|
||||
ec, err_msg = job_state.GetError
|
||||
log_debug("Background process for %s is %d" %
|
||||
(str(command), process.pid))
|
||||
|
||||
lines_iterator = iter(process.stdout.readline, b"")
|
||||
for line in lines_iterator:
|
||||
line_str = line.decode("utf-8")
|
||||
|
||||
# Check to see if the line has the correct number of separators
|
||||
try:
|
||||
if line_str.count(':') == 2:
|
||||
(device, ignore, percentage) = line_str.split(':')
|
||||
job_state.Percent = round(
|
||||
float(percentage.strip()[:-1]), 1)
|
||||
except ValueError:
|
||||
log_error("Trying to parse percentage which failed for %s" %
|
||||
line_str)
|
||||
|
||||
out = process.communicate()
|
||||
|
||||
if process.returncode == 0:
|
||||
job_state.Percent = 100
|
||||
else:
|
||||
raise dbus.exceptions.DBusException(
|
||||
interface_name,
|
||||
'Exit code %s, stderr = %s' % (str(ec), err_msg))
|
||||
'Exit code %s, stderr = %s' % (str(process.returncode), out[1]))
|
||||
|
||||
cfg.load()
|
||||
return '/'
|
||||
@@ -85,8 +104,6 @@ def move(interface_name, lv_name, pv_src_obj, pv_source_range,
|
||||
|
||||
pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
|
||||
|
||||
# Generate the command line for this command, but don't
|
||||
# execute it.
|
||||
cmd = pv_move_lv_cmd(move_options,
|
||||
lv_name,
|
||||
pv_src.lvm_id,
|
||||
@@ -109,106 +126,3 @@ def merge(interface_name, lv_uuid, lv_name, merge_options, job_state):
|
||||
raise dbus.exceptions.DBusException(
|
||||
interface_name,
|
||||
'LV with uuid %s and name %s not present!' % (lv_uuid, lv_name))
|
||||
|
||||
|
||||
def background_reaper():
|
||||
while cfg.run.value != 0:
|
||||
with _rlock:
|
||||
num_threads = len(_thread_list) - 1
|
||||
if num_threads >= 0:
|
||||
for i in range(num_threads, -1, -1):
|
||||
_thread_list[i].join(0)
|
||||
if not _thread_list[i].is_alive():
|
||||
log_debug("Removing thread: %s" % _thread_list[i].name)
|
||||
_thread_list.pop(i)
|
||||
|
||||
time.sleep(3)
|
||||
|
||||
|
||||
def background_execute(command, background_job):
|
||||
|
||||
# Wrap this whole operation in an exception handler, otherwise if we
|
||||
# hit a code bug we will silently exit this thread without anyone being
|
||||
# the wiser.
|
||||
try:
|
||||
# We need to execute these command stand alone by forking & exec'ing
|
||||
# the command always!
|
||||
command.insert(0, cfg.LVM_CMD)
|
||||
process = subprocess.Popen(command, stdout=subprocess.PIPE,
|
||||
env=os.environ,
|
||||
stderr=subprocess.PIPE, close_fds=True)
|
||||
|
||||
log_debug("Background process for %s is %d" %
|
||||
(str(command), process.pid))
|
||||
|
||||
lines_iterator = iter(process.stdout.readline, b"")
|
||||
for line in lines_iterator:
|
||||
line_str = line.decode("utf-8")
|
||||
|
||||
# Check to see if the line has the correct number of separators
|
||||
try:
|
||||
if line_str.count(':') == 2:
|
||||
(device, ignore, percentage) = line_str.split(':')
|
||||
background_job.Percent = round(
|
||||
float(percentage.strip()[:-1]), 1)
|
||||
except ValueError:
|
||||
log_error("Trying to parse percentage which failed for %s" %
|
||||
line_str)
|
||||
|
||||
out = process.communicate()
|
||||
|
||||
if process.returncode == 0:
|
||||
background_job.Percent = 100
|
||||
else:
|
||||
log_error("Failed to execute background job %s, STDERR= %s"
|
||||
% (str(command), out[1]))
|
||||
|
||||
background_job.set_result(process.returncode, out[1])
|
||||
log_debug("Background process %d complete!" % process.pid)
|
||||
|
||||
except Exception:
|
||||
# In the unlikely event that we blow up, we need to unblock caller which
|
||||
# is waiting on an answer.
|
||||
st = traceback.format_exc()
|
||||
error = "Exception in background thread: \n%s" % st
|
||||
log_error(error)
|
||||
background_job.set_result(1, error)
|
||||
|
||||
|
||||
def add(command, reporting_job):
|
||||
# Create the thread, get it running and then add it to the list
|
||||
t = threading.Thread(
|
||||
target=background_execute,
|
||||
name="thread: " + ' '.join(command),
|
||||
args=(command, reporting_job))
|
||||
t.start()
|
||||
|
||||
with _rlock:
|
||||
_thread_list.append(t)
|
||||
|
||||
|
||||
def wait_thread(job, timeout, cb, cbe):
|
||||
# We need to put the wait on it's own thread, so that we don't block the
|
||||
# entire dbus queue processing thread
|
||||
try:
|
||||
cb(job.state.Wait(timeout))
|
||||
except Exception as e:
|
||||
cbe("Wait exception: %s" % str(e))
|
||||
return 0
|
||||
|
||||
|
||||
def add_wait(job, timeout, cb, cbe):
|
||||
|
||||
if timeout == 0:
|
||||
# Users are basically polling, do not create thread
|
||||
cb(job.Complete)
|
||||
else:
|
||||
t = threading.Thread(
|
||||
target=wait_thread,
|
||||
name="thread job.Wait: %s" % job.dbus_object_path(),
|
||||
args=(job, timeout, cb, cbe)
|
||||
)
|
||||
|
||||
t.start()
|
||||
with _rlock:
|
||||
_thread_list.append(t)
|
||||
|
@@ -11,20 +11,37 @@ from .pv import load_pvs
|
||||
from .vg import load_vgs
|
||||
from .lv import load_lvs
|
||||
from . import cfg
|
||||
from .utils import MThreadRunner, log_debug
|
||||
|
||||
|
||||
def load(refresh=True, emit_signal=True, cache_refresh=True, log=True):
|
||||
def _main_thread_load(refresh=True, emit_signal=True):
|
||||
num_total_changes = 0
|
||||
|
||||
num_total_changes += load_pvs(
|
||||
refresh=refresh,
|
||||
emit_signal=emit_signal,
|
||||
cache_refresh=False)[1]
|
||||
num_total_changes += load_vgs(
|
||||
refresh=refresh,
|
||||
emit_signal=emit_signal,
|
||||
cache_refresh=False)[1]
|
||||
num_total_changes += load_lvs(
|
||||
refresh=refresh,
|
||||
emit_signal=emit_signal,
|
||||
cache_refresh=False)[1]
|
||||
|
||||
return num_total_changes
|
||||
|
||||
|
||||
def load(refresh=True, emit_signal=True, cache_refresh=True, log=True,
|
||||
need_main_thread=True):
|
||||
# Go through and load all the PVs, VGs and LVs
|
||||
if cache_refresh:
|
||||
cfg.db.refresh(log)
|
||||
|
||||
num_total_changes += load_pvs(refresh=refresh, emit_signal=emit_signal,
|
||||
cache_refresh=False)[1]
|
||||
num_total_changes += load_vgs(refresh=refresh, emit_signal=emit_signal,
|
||||
cache_refresh=False)[1]
|
||||
num_total_changes += load_lvs(refresh=refresh, emit_signal=emit_signal,
|
||||
cache_refresh=False)[1]
|
||||
if need_main_thread:
|
||||
rc = MThreadRunner(_main_thread_load, refresh, emit_signal).done()
|
||||
else:
|
||||
rc = _main_thread_load(refresh, emit_signal)
|
||||
|
||||
return num_total_changes
|
||||
return rc
|
||||
|
@@ -8,12 +8,54 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from .automatedproperties import AutomatedProperties
|
||||
from .utils import job_obj_path_generate
|
||||
from .utils import job_obj_path_generate, mt_async_result, log_debug
|
||||
from . import cfg
|
||||
from .cfg import JOB_INTERFACE
|
||||
import dbus
|
||||
import threading
|
||||
from . import background
|
||||
from gi.repository import GLib
|
||||
|
||||
|
||||
# Class that handles a client waiting for something to be complete. We either
|
||||
# get a timeout or the operation is done.
|
||||
class WaitingClient(object):
|
||||
|
||||
# A timeout occurred
|
||||
@staticmethod
|
||||
def _timeout(wc):
|
||||
with wc.rlock:
|
||||
if wc.in_use:
|
||||
wc.in_use = False
|
||||
# Remove ourselves from waiting client
|
||||
wc.job_state.remove_waiting_client(wc)
|
||||
wc.timer_id = -1
|
||||
mt_async_result(wc.cb, wc.job_state.Complete)
|
||||
wc.job_state = None
|
||||
|
||||
def __init__(self, job_state, tmo, cb, cbe):
|
||||
self.rlock = threading.RLock()
|
||||
self.job_state = job_state
|
||||
self.cb = cb
|
||||
self.cbe = cbe
|
||||
self.in_use = True # Indicates if object is in play
|
||||
self.timer_id = -1
|
||||
if tmo > 0:
|
||||
self.timer_id = GLib.timeout_add_seconds(
|
||||
tmo, WaitingClient._timeout, self)
|
||||
|
||||
# The job finished before the timer popped and we are being notified that
|
||||
# it's done
|
||||
def notify(self):
|
||||
with self.rlock:
|
||||
if self.in_use:
|
||||
self.in_use = False
|
||||
# Clear timer
|
||||
if self.timer_id != -1:
|
||||
GLib.source_remove(self.timer_id)
|
||||
self.timer_id = -1
|
||||
|
||||
mt_async_result(self.cb, self.job_state.Complete)
|
||||
self.job_state = None
|
||||
|
||||
|
||||
# noinspection PyPep8Naming
|
||||
@@ -24,9 +66,9 @@ class JobState(object):
|
||||
self._percent = 0
|
||||
self._complete = False
|
||||
self._request = request
|
||||
self._cond = threading.Condition(self.rlock)
|
||||
self._ec = 0
|
||||
self._stderr = ''
|
||||
self._waiting_clients = []
|
||||
|
||||
# This is an lvm command that is just taking too long and doesn't
|
||||
# support background operation
|
||||
@@ -57,7 +99,7 @@ class JobState(object):
|
||||
with self.rlock:
|
||||
self._complete = value
|
||||
self._percent = 100
|
||||
self._cond.notify_all()
|
||||
self.notify_waiting_clients()
|
||||
|
||||
@property
|
||||
def GetError(self):
|
||||
@@ -71,29 +113,10 @@ class JobState(object):
|
||||
else:
|
||||
return (-1, 'Job is not complete!')
|
||||
|
||||
def set_result(self, ec, msg):
|
||||
with self.rlock:
|
||||
self.Complete = True
|
||||
self._ec = ec
|
||||
self._stderr = msg
|
||||
|
||||
def dtor(self):
|
||||
with self.rlock:
|
||||
self._request = None
|
||||
|
||||
def Wait(self, timeout):
|
||||
try:
|
||||
with self._cond:
|
||||
# Check to see if we are done, before we wait
|
||||
if not self.Complete:
|
||||
if timeout != -1:
|
||||
self._cond.wait(timeout)
|
||||
else:
|
||||
self._cond.wait()
|
||||
return self.Complete
|
||||
except RuntimeError:
|
||||
return False
|
||||
|
||||
@property
|
||||
def Result(self):
|
||||
with self.rlock:
|
||||
@@ -101,6 +124,36 @@ class JobState(object):
|
||||
return self._request.result()
|
||||
return '/'
|
||||
|
||||
def add_waiting_client(self, client):
|
||||
with self.rlock:
|
||||
# Avoid race condition where it goes complete before we get added
|
||||
# to the list of waiting clients
|
||||
if self.Complete:
|
||||
client.notify()
|
||||
else:
|
||||
self._waiting_clients.append(client)
|
||||
|
||||
def remove_waiting_client(self, client):
|
||||
# If a waiting client timer pops before the job is done we will allow
|
||||
# the client to remove themselves from the list. As we have a lock
|
||||
# here and a lock in the waiting client too, and they can be obtained
|
||||
# in different orders, a dead lock can occur.
|
||||
# As this remove is really optional, we will try to acquire the lock
|
||||
# and remove. If we are unsuccessful it's not fatal, we just delay
|
||||
# the time when the objects can be garbage collected by python
|
||||
if self.rlock.acquire(False):
|
||||
try:
|
||||
self._waiting_clients.remove(client)
|
||||
finally:
|
||||
self.rlock.release()
|
||||
|
||||
def notify_waiting_clients(self):
|
||||
with self.rlock:
|
||||
for c in self._waiting_clients:
|
||||
c.notify()
|
||||
|
||||
self._waiting_clients = []
|
||||
|
||||
|
||||
# noinspection PyPep8Naming
|
||||
class Job(AutomatedProperties):
|
||||
@@ -122,10 +175,6 @@ class Job(AutomatedProperties):
|
||||
def Percent(self):
|
||||
return dbus.Double(float(self.state.Percent))
|
||||
|
||||
@Percent.setter
|
||||
def Percent(self, value):
|
||||
self.state.Percent = value
|
||||
|
||||
@property
|
||||
def Complete(self):
|
||||
return dbus.Boolean(self.state.Complete)
|
||||
@@ -138,9 +187,6 @@ class Job(AutomatedProperties):
|
||||
def GetError(self):
|
||||
return dbus.Struct(self.state.GetError, signature="(is)")
|
||||
|
||||
def set_result(self, ec, msg):
|
||||
self.state.set_result(ec, msg)
|
||||
|
||||
@dbus.service.method(dbus_interface=JOB_INTERFACE)
|
||||
def Remove(self):
|
||||
if self.state.Complete:
|
||||
@@ -155,7 +201,11 @@ class Job(AutomatedProperties):
|
||||
out_signature='b',
|
||||
async_callbacks=('cb', 'cbe'))
|
||||
def Wait(self, timeout, cb, cbe):
|
||||
background.add_wait(self, timeout, cb, cbe)
|
||||
if timeout == 0 or self.state.Complete:
|
||||
cb(dbus.Boolean(self.state.Complete))
|
||||
else:
|
||||
self.state.add_waiting_client(
|
||||
WaitingClient(self.state, timeout, cb, cbe))
|
||||
|
||||
@property
|
||||
def Result(self):
|
||||
|
@@ -21,7 +21,7 @@ from .utils import n, n32
|
||||
from .loader import common
|
||||
from .state import State
|
||||
from . import background
|
||||
from .utils import round_size
|
||||
from .utils import round_size, mt_remove_dbus_objects
|
||||
from .job import JobState
|
||||
|
||||
|
||||
@@ -415,7 +415,6 @@ class Lv(LvCommon):
|
||||
rc, out, err = cmdhandler.lv_remove(lv_name, remove_options)
|
||||
|
||||
if rc == 0:
|
||||
cfg.om.remove_object(dbo, True)
|
||||
cfg.load()
|
||||
else:
|
||||
# Need to work on error handling, need consistent
|
||||
@@ -515,15 +514,9 @@ class Lv(LvCommon):
|
||||
rc, out, err = cmdhandler.vg_lv_snapshot(
|
||||
lv_name, snapshot_options, name, optional_size)
|
||||
if rc == 0:
|
||||
return_path = '/'
|
||||
cfg.load()
|
||||
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
|
||||
lvs = load_lvs([full_name], emit_signal=True)[0]
|
||||
for l in lvs:
|
||||
return_path = l.dbus_object_path()
|
||||
|
||||
# Refresh self and all included PVs
|
||||
cfg.load(cache_refresh=False)
|
||||
return return_path
|
||||
return cfg.om.get_object_path_by_lvm_id(full_name)
|
||||
else:
|
||||
raise dbus.exceptions.DBusException(
|
||||
LV_INTERFACE,
|
||||
@@ -752,9 +745,8 @@ class LvThinPool(Lv):
|
||||
lv_name, create_options, name, size_bytes)
|
||||
if rc == 0:
|
||||
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
|
||||
lvs = load_lvs([full_name], emit_signal=True)[0]
|
||||
for l in lvs:
|
||||
lv_created = l.dbus_object_path()
|
||||
cfg.load()
|
||||
lv_created = cfg.om.get_object_path_by_lvm_id(full_name)
|
||||
else:
|
||||
raise dbus.exceptions.DBusException(
|
||||
LV_INTERFACE,
|
||||
@@ -816,8 +808,7 @@ class LvCachePool(Lv):
|
||||
# When we cache an LV, the cache pool and the lv that is getting
|
||||
# cached need to be removed from the object manager and
|
||||
# re-created as their interfaces have changed!
|
||||
cfg.om.remove_object(dbo, emit_signal=True)
|
||||
cfg.om.remove_object(lv_to_cache, emit_signal=True)
|
||||
mt_remove_dbus_objects((dbo, lv_to_cache))
|
||||
cfg.load()
|
||||
|
||||
lv_converted = cfg.om.get_object_path_by_lvm_id(fcn)
|
||||
@@ -879,8 +870,7 @@ class LvCacheLv(Lv):
|
||||
if rc == 0:
|
||||
# The cache pool gets removed as hidden and put back to
|
||||
# visible, so lets delete
|
||||
cfg.om.remove_object(cache_pool, emit_signal=True)
|
||||
cfg.om.remove_object(dbo, emit_signal=True)
|
||||
mt_remove_dbus_objects((cache_pool, dbo))
|
||||
cfg.load()
|
||||
|
||||
uncached_lv_path = cfg.om.get_object_path_by_lvm_id(lv_name)
|
||||
|
@@ -22,7 +22,6 @@ from . import lvmdb
|
||||
from gi.repository import GLib
|
||||
from .fetch import load
|
||||
from .manager import Manager
|
||||
from .background import background_reaper
|
||||
import traceback
|
||||
import queue
|
||||
from . import udevwatch
|
||||
@@ -64,6 +63,7 @@ def _discard_pending_refreshes():
|
||||
|
||||
def process_request():
|
||||
while cfg.run.value != 0:
|
||||
# noinspection PyBroadException
|
||||
try:
|
||||
req = cfg.worker_q.get(True, 5)
|
||||
|
||||
@@ -85,7 +85,7 @@ def process_request():
|
||||
log_debug(
|
||||
"Inspect method %s for too many refreshes" %
|
||||
(str(req.method)))
|
||||
log_debug("Complete ")
|
||||
log_debug("Method complete ")
|
||||
except queue.Empty:
|
||||
pass
|
||||
except Exception:
|
||||
@@ -156,14 +156,11 @@ def main():
|
||||
|
||||
cfg.db = lvmdb.DataStore(cfg.args.use_json)
|
||||
|
||||
# Start up thread to monitor pv moves
|
||||
thread_list.append(
|
||||
threading.Thread(target=background_reaper, name="pv_move_reaper"))
|
||||
|
||||
# Using a thread to process requests.
|
||||
# Using a thread to process requests, we cannot hang the dbus library
|
||||
# thread that is handling the dbus interface
|
||||
thread_list.append(threading.Thread(target=process_request))
|
||||
|
||||
cfg.load(refresh=False, emit_signal=False)
|
||||
cfg.load(refresh=False, emit_signal=False, need_main_thread=False)
|
||||
cfg.loop = GLib.MainLoop()
|
||||
|
||||
for process in thread_list:
|
||||
|
@@ -42,12 +42,10 @@ class Manager(AutomatedProperties):
|
||||
raise dbus.exceptions.DBusException(
|
||||
MANAGER_INTERFACE, "PV Already exists!")
|
||||
|
||||
created_pv = []
|
||||
rc, out, err = cmdhandler.pv_create(create_options, [device])
|
||||
if rc == 0:
|
||||
pvs = load_pvs([device], emit_signal=True)[0]
|
||||
for p in pvs:
|
||||
created_pv = p.dbus_object_path()
|
||||
cfg.load()
|
||||
created_pv = cfg.om.get_object_path_by_lvm_id(device)
|
||||
else:
|
||||
raise dbus.exceptions.DBusException(
|
||||
MANAGER_INTERFACE,
|
||||
@@ -80,20 +78,14 @@ class Manager(AutomatedProperties):
|
||||
MANAGER_INTERFACE, 'object path = %s not found' % p)
|
||||
|
||||
rc, out, err = cmdhandler.vg_create(create_options, pv_devices, name)
|
||||
created_vg = "/"
|
||||
|
||||
if rc == 0:
|
||||
vgs = load_vgs([name], emit_signal=True)[0]
|
||||
for v in vgs:
|
||||
created_vg = v.dbus_object_path()
|
||||
|
||||
# Update the PVS
|
||||
load_pvs(refresh=True, emit_signal=True, cache_refresh=False)
|
||||
cfg.load()
|
||||
return cfg.om.get_object_path_by_lvm_id(name)
|
||||
else:
|
||||
raise dbus.exceptions.DBusException(
|
||||
MANAGER_INTERFACE,
|
||||
'Exit code %s, stderr = %s' % (str(rc), err))
|
||||
return created_vg
|
||||
|
||||
@dbus.service.method(
|
||||
dbus_interface=MANAGER_INTERFACE,
|
||||
|
@@ -18,7 +18,7 @@ from .utils import vg_obj_path_generate, n, pv_obj_path_generate, \
|
||||
from .loader import common
|
||||
from .request import RequestEntry
|
||||
from .state import State
|
||||
from .utils import round_size
|
||||
from .utils import round_size, mt_remove_dbus_objects
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
@@ -140,7 +140,7 @@ class Pv(AutomatedProperties):
|
||||
if dbo:
|
||||
rc, out, err = cmdhandler.pv_remove(pv_name, remove_options)
|
||||
if rc == 0:
|
||||
cfg.om.remove_object(dbo, True)
|
||||
mt_remove_dbus_objects((dbo,))
|
||||
else:
|
||||
# Need to work on error handling, need consistent
|
||||
raise dbus.exceptions.DBusException(
|
||||
@@ -174,7 +174,7 @@ class Pv(AutomatedProperties):
|
||||
rc, out, err = cmdhandler.pv_resize(pv_name, new_size_bytes,
|
||||
resize_options)
|
||||
if rc == 0:
|
||||
dbo.refresh()
|
||||
cfg.load()
|
||||
else:
|
||||
raise dbus.exceptions.DBusException(
|
||||
PV_INTERFACE,
|
||||
|
@@ -13,7 +13,7 @@ from gi.repository import GLib
|
||||
from .job import Job
|
||||
from . import cfg
|
||||
import traceback
|
||||
from .utils import log_error
|
||||
from .utils import log_error, mt_async_result
|
||||
|
||||
|
||||
class RequestEntry(object):
|
||||
@@ -57,9 +57,9 @@ class RequestEntry(object):
|
||||
self._job = Job(self, self._job_state)
|
||||
cfg.om.register_object(self._job, True)
|
||||
if self._return_tuple:
|
||||
self.cb(('/', self._job.dbus_object_path()))
|
||||
mt_async_result(self.cb, ('/', self._job.dbus_object_path()))
|
||||
else:
|
||||
self.cb(self._job.dbus_object_path())
|
||||
mt_async_result(self.cb, self._job.dbus_object_path())
|
||||
|
||||
def run_cmd(self):
|
||||
try:
|
||||
@@ -110,9 +110,9 @@ class RequestEntry(object):
|
||||
if error_rc == 0:
|
||||
if self.cb:
|
||||
if self._return_tuple:
|
||||
self.cb((result, '/'))
|
||||
mt_async_result(self.cb, (result, '/'))
|
||||
else:
|
||||
self.cb(result)
|
||||
mt_async_result(self.cb, result)
|
||||
else:
|
||||
if self.cb_error:
|
||||
if not error_exception:
|
||||
@@ -123,7 +123,7 @@ class RequestEntry(object):
|
||||
else:
|
||||
error_exception = Exception(error_msg)
|
||||
|
||||
self.cb_error(error_exception)
|
||||
mt_async_result(self.cb_error, error_exception)
|
||||
else:
|
||||
# We have a job and it's complete, indicate that it's done.
|
||||
# TODO: We need to signal the job is done too.
|
||||
|
@@ -17,6 +17,8 @@ import datetime
|
||||
|
||||
import dbus
|
||||
from lvmdbusd import cfg
|
||||
from gi.repository import GLib
|
||||
import threading
|
||||
|
||||
|
||||
STDOUT_TTY = os.isatty(sys.stdout.fileno())
|
||||
@@ -494,3 +496,64 @@ def validate_tag(interface, tag):
|
||||
raise dbus.exceptions.DBusException(
|
||||
interface, 'tag (%s) contains invalid character, allowable set(%s)'
|
||||
% (tag, _ALLOWABLE_TAG_CH))
|
||||
|
||||
|
||||
# The methods below which start with mt_* are used to execute the desired code
|
||||
# on the the main thread of execution to alleviate any issues the dbus-python
|
||||
# library with regards to multi-threaded access. Essentially, we are trying to
|
||||
# ensure all dbus library interaction is done from the same thread!
|
||||
|
||||
|
||||
def _async_result(call_back, results):
|
||||
log_debug('Results = %s' % str(results))
|
||||
call_back(results)
|
||||
|
||||
# Return result in main thread
|
||||
def mt_async_result(call_back, results):
|
||||
GLib.idle_add(_async_result, call_back, results)
|
||||
|
||||
|
||||
# Run the supplied function and arguments on the main thread and wait for them
|
||||
# to complete while allowing the ability to get the return value too.
|
||||
#
|
||||
# Example:
|
||||
# result = MThreadRunner(foo, arg1, arg2).done()
|
||||
#
|
||||
class MThreadRunner(object):
|
||||
|
||||
@staticmethod
|
||||
def runner(obj):
|
||||
obj._run()
|
||||
with obj.cond:
|
||||
obj.function_complete = True
|
||||
obj.cond.notify_all()
|
||||
|
||||
def __init__(self, function, *args):
|
||||
self.f = function
|
||||
self.rc = None
|
||||
self.args = args
|
||||
self.function_complete = False
|
||||
self.cond = threading.Condition(threading.Lock())
|
||||
|
||||
def done(self):
|
||||
GLib.idle_add(MThreadRunner.runner, self)
|
||||
with self.cond:
|
||||
if not self.function_complete:
|
||||
self.cond.wait()
|
||||
return self.rc
|
||||
|
||||
def _run(self):
|
||||
if len(self.args):
|
||||
self.rc = self.f(*self.args)
|
||||
else:
|
||||
self.rc = self.f()
|
||||
|
||||
|
||||
def _remove_objects(dbus_objects_rm):
|
||||
for o in dbus_objects_rm:
|
||||
cfg.om.remove_object(o, emit_signal=True)
|
||||
|
||||
|
||||
# Remove dbus objects from main thread
|
||||
def mt_remove_dbus_objects(objs):
|
||||
MThreadRunner(_remove_objects, objs).done()
|
||||
|
@@ -19,7 +19,7 @@ from .request import RequestEntry
|
||||
from .loader import common
|
||||
from .state import State
|
||||
from . import background
|
||||
from .utils import round_size
|
||||
from .utils import round_size, mt_remove_dbus_objects
|
||||
from .job import JobState
|
||||
|
||||
|
||||
@@ -191,14 +191,7 @@ class Vg(AutomatedProperties):
|
||||
rc, out, err = cmdhandler.vg_remove(vg_name, remove_options)
|
||||
|
||||
if rc == 0:
|
||||
# Remove the VG
|
||||
cfg.om.remove_object(dbo, True)
|
||||
|
||||
# If an LV has hidden LVs, things can get quite involved,
|
||||
# especially if it's the last thin pool to get removed, so
|
||||
# lets refresh all
|
||||
cfg.load()
|
||||
|
||||
else:
|
||||
# Need to work on error handling, need consistent
|
||||
raise dbus.exceptions.DBusException(
|
||||
@@ -605,9 +598,7 @@ class Vg(AutomatedProperties):
|
||||
rc, out, err = create_method(
|
||||
md.lv_full_name(), data.lv_full_name(), create_options)
|
||||
if rc == 0:
|
||||
cfg.om.remove_object(md, emit_signal=True)
|
||||
cfg.om.remove_object(data, emit_signal=True)
|
||||
|
||||
mt_remove_dbus_objects((md, data))
|
||||
cache_pool_lv = Vg.fetch_new_lv(vg_name, new_name)
|
||||
else:
|
||||
raise dbus.exceptions.DBusException(
|
||||
|
@@ -370,6 +370,11 @@ void activation_exit(void)
|
||||
{
|
||||
}
|
||||
|
||||
int raid4_is_supported(struct cmd_context *cmd, const struct segment_type *segtype)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lv_is_active(const struct logical_volume *lv)
|
||||
{
|
||||
return 0;
|
||||
@@ -1489,6 +1494,26 @@ out:
|
||||
return r || l;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if "raid4" @segtype is supported by kernel.
|
||||
*
|
||||
* if segment type is not raid4, return 1.
|
||||
*/
|
||||
int raid4_is_supported(struct cmd_context *cmd, const struct segment_type *segtype)
|
||||
{
|
||||
unsigned attrs;
|
||||
|
||||
if (segtype_is_raid4(segtype) &&
|
||||
(!segtype->ops->target_present ||
|
||||
!segtype->ops->target_present(cmd, NULL, &attrs) ||
|
||||
!(attrs & RAID_FEATURE_RAID4))) {
|
||||
log_error("RAID module does not support RAID4.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lv_is_active(const struct logical_volume *lv)
|
||||
{
|
||||
return _lv_is_active(lv, NULL, NULL, NULL);
|
||||
@@ -1683,7 +1708,7 @@ int target_register_events(struct cmd_context *cmd, const char *dso, const struc
|
||||
if (!r)
|
||||
return_0;
|
||||
|
||||
log_info("%s %s for events", set ? "Monitored" : "Unmonitored", uuid);
|
||||
log_very_verbose("%s %s for events", set ? "Monitored" : "Unmonitored", uuid);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -99,6 +99,7 @@ int target_present(struct cmd_context *cmd, const char *target_name,
|
||||
int use_modprobe);
|
||||
int target_version(const char *target_name, uint32_t *maj,
|
||||
uint32_t *min, uint32_t *patchlevel);
|
||||
int raid4_is_supported(struct cmd_context *cmd, const struct segment_type *segtype);
|
||||
int lvm_dm_prefix_check(int major, int minor, const char *prefix);
|
||||
int list_segment_modules(struct dm_pool *mem, const struct lv_segment *seg,
|
||||
struct dm_list *modules);
|
||||
|
@@ -40,7 +40,7 @@ static int _extract_pattern(struct dm_pool *mem, const char *pat,
|
||||
break;
|
||||
|
||||
default:
|
||||
log_info("pattern must begin with 'a' or 'r'");
|
||||
log_error("Pattern must begin with 'a' or 'r'.");
|
||||
return 0;
|
||||
}
|
||||
pat++;
|
||||
@@ -77,7 +77,7 @@ static int _extract_pattern(struct dm_pool *mem, const char *pat,
|
||||
*/
|
||||
ptr = r + strlen(r) - 1;
|
||||
if (*ptr != sep) {
|
||||
log_info("invalid separator at end of regex");
|
||||
log_error("Invalid separator at end of regex.");
|
||||
return 0;
|
||||
}
|
||||
*ptr = '\0';
|
||||
|
@@ -168,7 +168,7 @@ static int _parse_dev(const char *file, FILE *fp, dev_t *result)
|
||||
}
|
||||
|
||||
if (sscanf(buffer, "%u:%u", &major, &minor) != 2) {
|
||||
log_info("sysfs device file not correct format");
|
||||
log_error("Incorrect format for sysfs device file: %s.", file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -140,18 +140,18 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
sector + scan_sector);
|
||||
}
|
||||
if (xlate64(lh->sector_xl) != sector + scan_sector) {
|
||||
log_info("%s: Label for sector %" PRIu64
|
||||
" found at sector %" PRIu64
|
||||
" - ignoring", dev_name(dev),
|
||||
(uint64_t)xlate64(lh->sector_xl),
|
||||
sector + scan_sector);
|
||||
log_very_verbose("%s: Label for sector %" PRIu64
|
||||
" found at sector %" PRIu64
|
||||
" - ignoring", dev_name(dev),
|
||||
(uint64_t)xlate64(lh->sector_xl),
|
||||
sector + scan_sector);
|
||||
continue;
|
||||
}
|
||||
if (calc_crc(INITIAL_CRC, (uint8_t *)&lh->offset_xl, LABEL_SIZE -
|
||||
((uint8_t *) &lh->offset_xl - (uint8_t *) lh)) !=
|
||||
xlate32(lh->crc_xl)) {
|
||||
log_info("Label checksum incorrect on %s - "
|
||||
"ignoring", dev_name(dev));
|
||||
log_very_verbose("Label checksum incorrect on %s - "
|
||||
"ignoring", dev_name(dev));
|
||||
continue;
|
||||
}
|
||||
if (found)
|
||||
@@ -243,8 +243,8 @@ int label_remove(struct device *dev)
|
||||
}
|
||||
|
||||
if (wipe) {
|
||||
log_info("%s: Wiping label at sector %" PRIu64,
|
||||
dev_name(dev), sector);
|
||||
log_very_verbose("%s: Wiping label at sector %" PRIu64,
|
||||
dev_name(dev), sector);
|
||||
if (!dev_write(dev, sector << SECTOR_SHIFT, LABEL_SIZE,
|
||||
buf)) {
|
||||
log_error("Failed to remove label from %s at "
|
||||
@@ -333,9 +333,9 @@ int label_write(struct device *dev, struct label *label)
|
||||
if (!dev_open(dev))
|
||||
return_0;
|
||||
|
||||
log_info("%s: Writing label to sector %" PRIu64 " with stored offset %"
|
||||
PRIu32 ".", dev_name(dev), label->sector,
|
||||
xlate32(lh->offset_xl));
|
||||
log_very_verbose("%s: Writing label to sector %" PRIu64 " with stored offset %"
|
||||
PRIu32 ".", dev_name(dev), label->sector,
|
||||
xlate32(lh->offset_xl));
|
||||
if (!dev_write(dev, label->sector << SECTOR_SHIFT, LABEL_SIZE, buf)) {
|
||||
log_debug_devs("Failed to write label to %s", dev_name(dev));
|
||||
r = 0;
|
||||
|
@@ -67,7 +67,7 @@ struct log_stream_item {
|
||||
char *buffer;
|
||||
};
|
||||
|
||||
struct log_stream {
|
||||
static struct log_stream {
|
||||
struct log_stream_item out;
|
||||
struct log_stream_item err;
|
||||
struct log_stream_item report;
|
||||
@@ -476,9 +476,9 @@ static void _vprint_log(int level, const char *file, int line, int dm_errno_or_c
|
||||
int bufused, n;
|
||||
const char *trformat; /* Translated format string */
|
||||
char *newbuf;
|
||||
int use_stderr = level & _LOG_STDERR;
|
||||
int log_once = level & _LOG_ONCE;
|
||||
int log_bypass_report = level & _LOG_BYPASS_REPORT;
|
||||
int use_stderr = log_stderr(level);
|
||||
int log_once = log_once(level);
|
||||
int log_bypass_report = log_bypass_report(level);
|
||||
int fatal_internal_error = 0;
|
||||
size_t msglen;
|
||||
const char *indent_spaces = "";
|
||||
@@ -489,7 +489,7 @@ static void _vprint_log(int level, const char *file, int line, int dm_errno_or_c
|
||||
struct dm_report *orig_report;
|
||||
int logged_via_report = 0;
|
||||
|
||||
level &= ~(_LOG_STDERR|_LOG_ONCE|_LOG_BYPASS_REPORT);
|
||||
level = log_level(level);
|
||||
|
||||
if (_abort_on_internal_errors_env_present < 0) {
|
||||
if ((env_str = getenv("DM_ABORT_ON_INTERNAL_ERRORS"))) {
|
||||
@@ -715,8 +715,8 @@ void print_log_libdm(int level, const char *file, int line, int dm_errno_or_clas
|
||||
* LOG_WARN level and it's not going to stderr (so we're
|
||||
* printing common message that is not an error/warning).
|
||||
*/
|
||||
if (!(level & _LOG_STDERR) &&
|
||||
((level & ~(_LOG_STDERR|_LOG_ONCE|_LOG_BYPASS_REPORT)) == _LOG_WARN))
|
||||
if (!log_stderr(level) &&
|
||||
(log_level(level) == _LOG_WARN))
|
||||
level |= _LOG_BYPASS_REPORT;
|
||||
|
||||
_log_stream.out.stream = report_stream;
|
||||
|
@@ -50,6 +50,10 @@
|
||||
#define _LOG_STDERR 0x0080 /* force things to go to stderr, even if loglevel would make them go to stdout */
|
||||
#define _LOG_ONCE 0x0100 /* downgrade to NOTICE if this has been already logged */
|
||||
#define _LOG_BYPASS_REPORT 0x0200 /* do not log through report even if report available */
|
||||
#define log_level(x) ((x) & 0x0f) /* obtain message level */
|
||||
#define log_stderr(x) ((x) & _LOG_STDERR) /* obtain stderr bit */
|
||||
#define log_once(x) ((x) & _LOG_ONCE) /* obtain once bit */
|
||||
#define log_bypass_report(x) ((x) & _LOG_BYPASS_REPORT)/* obtain bypass bit */
|
||||
|
||||
#define INTERNAL_ERROR "Internal error: "
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -1418,6 +1418,7 @@ int lv_active_change(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
enum activation_change activate, int needs_exclusive)
|
||||
{
|
||||
const char *ay_with_mode = NULL;
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
|
||||
if (activate == CHANGE_ASY)
|
||||
ay_with_mode = "sh";
|
||||
@@ -1454,6 +1455,9 @@ deactivate:
|
||||
break;
|
||||
case CHANGE_ALY:
|
||||
case CHANGE_AAY:
|
||||
if (!raid4_is_supported(cmd, seg->segtype))
|
||||
goto no_raid4;
|
||||
|
||||
if (needs_exclusive || _lv_is_exclusive(lv)) {
|
||||
log_verbose("Activating logical volume %s exclusively locally.",
|
||||
display_lvname(lv));
|
||||
@@ -1468,6 +1472,9 @@ deactivate:
|
||||
break;
|
||||
case CHANGE_AEY:
|
||||
exclusive:
|
||||
if (!raid4_is_supported(cmd, seg->segtype))
|
||||
goto no_raid4;
|
||||
|
||||
log_verbose("Activating logical volume %s exclusively.",
|
||||
display_lvname(lv));
|
||||
if (!activate_lv_excl(cmd, lv))
|
||||
@@ -1476,6 +1483,9 @@ exclusive:
|
||||
case CHANGE_ASY:
|
||||
case CHANGE_AY:
|
||||
default:
|
||||
if (!raid4_is_supported(cmd, seg->segtype))
|
||||
goto no_raid4;
|
||||
|
||||
if (needs_exclusive || _lv_is_exclusive(lv))
|
||||
goto exclusive;
|
||||
log_verbose("Activating logical volume %s.", display_lvname(lv));
|
||||
@@ -1488,6 +1498,10 @@ exclusive:
|
||||
log_error("Failed to unlock logical volume %s.", display_lvname(lv));
|
||||
|
||||
return 1;
|
||||
|
||||
no_raid4:
|
||||
log_error("Failed to activate %s LV %s", lvseg_name(seg), display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *lv_active_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
|
@@ -1208,8 +1208,8 @@ int lv_raid_convert(struct logical_volume *lv,
|
||||
const uint32_t new_region_size,
|
||||
struct dm_list *allocate_pvs);
|
||||
int lv_raid_rebuild(struct logical_volume *lv, struct dm_list *rebuild_pvs);
|
||||
int lv_raid_replace(struct logical_volume *lv, struct dm_list *remove_pvs,
|
||||
struct dm_list *allocate_pvs);
|
||||
int lv_raid_replace(struct logical_volume *lv, int force,
|
||||
struct dm_list *remove_pvs, struct dm_list *allocate_pvs);
|
||||
int lv_raid_remove_missing(struct logical_volume *lv);
|
||||
int partial_raid_lv_supports_degraded_activation(const struct logical_volume *lv);
|
||||
/* -- metadata/raid_manip.c */
|
||||
|
@@ -266,19 +266,16 @@ static int _deactivate_and_remove_lvs(struct volume_group *vg, struct dm_list *r
|
||||
*
|
||||
* Returns: 1 if in-sync, 0 otherwise.
|
||||
*/
|
||||
#define _RAID_IN_SYNC_RETRIES 6
|
||||
static int _raid_in_sync(struct logical_volume *lv)
|
||||
{
|
||||
int retries = _RAID_IN_SYNC_RETRIES;
|
||||
dm_percent_t sync_percent;
|
||||
|
||||
if (seg_is_striped(first_seg(lv)))
|
||||
return 1;
|
||||
|
||||
if (!lv_raid_percent(lv, &sync_percent)) {
|
||||
log_error("Unable to determine sync status of %s/%s.",
|
||||
lv->vg->name, lv->name);
|
||||
return 0;
|
||||
}
|
||||
if (sync_percent == DM_PERCENT_0) {
|
||||
do {
|
||||
/*
|
||||
* FIXME We repeat the status read here to workaround an
|
||||
* unresolved kernel bug when we see 0 even though the
|
||||
@@ -290,14 +287,34 @@ static int _raid_in_sync(struct logical_volume *lv)
|
||||
lv->vg->name, lv->name);
|
||||
return 0;
|
||||
}
|
||||
if (sync_percent == DM_PERCENT_100)
|
||||
if (sync_percent > DM_PERCENT_0)
|
||||
break;
|
||||
if (retries == _RAID_IN_SYNC_RETRIES)
|
||||
log_warn("WARNING: Sync status for %s is inconsistent.",
|
||||
display_lvname(lv));
|
||||
}
|
||||
usleep(500000);
|
||||
} while (--retries);
|
||||
|
||||
return (sync_percent == DM_PERCENT_100) ? 1 : 0;
|
||||
}
|
||||
|
||||
/* Check if RaidLV @lv is synced or any raid legs of @lv are not synced */
|
||||
static int _raid_devs_sync_healthy(struct logical_volume *lv)
|
||||
{
|
||||
char *raid_health;
|
||||
|
||||
if (!_raid_in_sync(lv))
|
||||
return 0;
|
||||
|
||||
if (!seg_is_raid1(first_seg(lv)))
|
||||
return 1;
|
||||
|
||||
if (!lv_raid_dev_health(lv, &raid_health))
|
||||
return_0;
|
||||
|
||||
return (strchr(raid_health, 'a') || strchr(raid_health, 'D')) ? 0 : 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* _raid_remove_top_layer
|
||||
* @lv
|
||||
@@ -1054,6 +1071,7 @@ static int _extract_image_components(struct lv_segment *seg, uint32_t idx,
|
||||
/*
|
||||
* _raid_extract_images
|
||||
* @lv
|
||||
* @force: force a replacement in case of primary mirror leg
|
||||
* @new_count: The absolute count of images (e.g. '2' for a 2-way mirror)
|
||||
* @target_pvs: The list of PVs that are candidates for removal
|
||||
* @shift: If set, use _shift_and_rename_image_components().
|
||||
@@ -1068,7 +1086,8 @@ static int _extract_image_components(struct lv_segment *seg, uint32_t idx,
|
||||
*
|
||||
* Returns: 1 on success, 0 on failure
|
||||
*/
|
||||
static int _raid_extract_images(struct logical_volume *lv, uint32_t new_count,
|
||||
static int _raid_extract_images(struct logical_volume *lv,
|
||||
int force, uint32_t new_count,
|
||||
struct dm_list *target_pvs, int shift,
|
||||
struct dm_list *extracted_meta_lvs,
|
||||
struct dm_list *extracted_data_lvs)
|
||||
@@ -1136,11 +1155,16 @@ static int _raid_extract_images(struct logical_volume *lv, uint32_t new_count,
|
||||
!lv_is_on_pvs(seg_metalv(seg, s), target_pvs))
|
||||
continue;
|
||||
|
||||
if (!_raid_in_sync(lv) &&
|
||||
(!seg_is_mirrored(seg) || (s == 0))) {
|
||||
/*
|
||||
* Kernel may report raid LV in-sync but still
|
||||
* image devices may not be in-sync or faulty.
|
||||
*/
|
||||
if (!_raid_devs_sync_healthy(lv) &&
|
||||
(!seg_is_mirrored(seg) || (s == 0 && !force))) {
|
||||
log_error("Unable to extract %sRAID image"
|
||||
" while RAID array is not in-sync",
|
||||
seg_is_mirrored(seg) ? "primary " : "");
|
||||
" while RAID array is not in-sync%s",
|
||||
seg_is_mirrored(seg) ? "primary " : "",
|
||||
seg_is_mirrored(seg) ? " (use --force option to replace)" : "");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1185,7 +1209,7 @@ static int _raid_remove_images(struct logical_volume *lv,
|
||||
if (!removal_lvs)
|
||||
removal_lvs = &removed_lvs;
|
||||
|
||||
if (!_raid_extract_images(lv, new_count, allocate_pvs, 1,
|
||||
if (!_raid_extract_images(lv, 0, new_count, allocate_pvs, 1,
|
||||
removal_lvs, removal_lvs)) {
|
||||
log_error("Failed to extract images from %s/%s",
|
||||
lv->vg->name, lv->name);
|
||||
@@ -1375,7 +1399,7 @@ int lv_raid_split(struct logical_volume *lv, const char *split_name,
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!_raid_extract_images(lv, new_count, splittable_pvs, 1,
|
||||
if (!_raid_extract_images(lv, 0, new_count, splittable_pvs, 1,
|
||||
&removal_lvs, &data_list)) {
|
||||
log_error("Failed to extract images from %s/%s",
|
||||
lv->vg->name, lv->name);
|
||||
@@ -2459,7 +2483,7 @@ static struct lv_segment *_convert_striped_to_raid0(struct logical_volume *lv,
|
||||
0 /* chunk_size */,
|
||||
0 /* seg->region_size */, 0u /* extents_copied */ ,
|
||||
NULL /* pvmove_source_seg */))) {
|
||||
log_error("Failed to allocate new raid0 segement for LV %s.", display_lvname(lv));
|
||||
log_error("Failed to allocate new raid0 segment for LV %s.", display_lvname(lv));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -2519,42 +2543,51 @@ static struct possible_takeover_reshape_type _possible_takeover_reshape_types[]
|
||||
{ .current_types = SEG_STRIPED_TARGET, /* linear, i.e. seg->area_count = 1 */
|
||||
.possible_types = SEG_RAID1,
|
||||
.current_areas = 1,
|
||||
.options = ALLOW_NONE },
|
||||
.options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
|
||||
{ .current_types = SEG_STRIPED_TARGET, /* linear, i.e. seg->area_count = 1 */
|
||||
.possible_types = SEG_RAID0|SEG_RAID0_META,
|
||||
.current_areas = 1,
|
||||
.options = ALLOW_STRIPE_SIZE },
|
||||
{ .current_types = SEG_STRIPED_TARGET, /* striped, i.e. seg->area_count > 1 */
|
||||
{ .current_types = SEG_STRIPED_TARGET, /* striped -> raid0*, i.e. seg->area_count > 1 */
|
||||
.possible_types = SEG_RAID0|SEG_RAID0_META,
|
||||
.current_areas = ~0U,
|
||||
.options = ALLOW_NONE },
|
||||
{ .current_types = SEG_STRIPED_TARGET, /* striped -> raid4 , i.e. seg->area_count > 1 */
|
||||
.possible_types = SEG_RAID4,
|
||||
.current_areas = ~0U,
|
||||
.options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
|
||||
/* raid0* -> */
|
||||
{ .current_types = SEG_RAID0|SEG_RAID0_META, /* seg->area_count = 1 */
|
||||
.possible_types = SEG_RAID1,
|
||||
.current_areas = 1,
|
||||
.options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
|
||||
{ .current_types = SEG_RAID0|SEG_RAID0_META, /* raid0* -> striped, i.e. seg->area_count > 1 */
|
||||
.possible_types = SEG_STRIPED_TARGET,
|
||||
.current_areas = ~0U,
|
||||
.options = ALLOW_NONE },
|
||||
{ .current_types = SEG_RAID0|SEG_RAID0_META, /* seg->area_count > 1 */
|
||||
{ .current_types = SEG_RAID0|SEG_RAID0_META, /* raid0* -> raid0*, i.e. seg->area_count > 1 */
|
||||
.possible_types = SEG_RAID0_META|SEG_RAID0,
|
||||
.current_areas = ~0U,
|
||||
.options = ALLOW_NONE },
|
||||
{ .current_types = SEG_RAID0|SEG_RAID0_META, /* raid0* -> raid4, i.e. seg->area_count > 1 */
|
||||
.possible_types = SEG_RAID4,
|
||||
.current_areas = ~0U,
|
||||
.options = ALLOW_NONE },
|
||||
{ .current_types = SEG_RAID0|SEG_RAID0_META, /* raid0 striped, i.e. seg->area_count > 0 */
|
||||
.options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
|
||||
/* raid4 -> -> */
|
||||
{ .current_types = SEG_RAID4, /* raid4 ->striped/raid0*, i.e. seg->area_count > 1 */
|
||||
.possible_types = SEG_STRIPED_TARGET|SEG_RAID0|SEG_RAID0_META,
|
||||
.current_areas = ~0U,
|
||||
.options = ALLOW_NONE },
|
||||
/* raid1 -> */
|
||||
/* raid1 -> mirror */
|
||||
{ .current_types = SEG_RAID1,
|
||||
.possible_types = SEG_RAID1|SEG_MIRROR,
|
||||
.possible_types = SEG_MIRROR,
|
||||
.current_areas = ~0U,
|
||||
.options = ALLOW_NONE },
|
||||
.options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
|
||||
/* mirror -> raid1 with arbitrary number of legs */
|
||||
{ .current_types = SEG_MIRROR,
|
||||
.possible_types = SEG_MIRROR|SEG_RAID1,
|
||||
.possible_types = SEG_RAID1,
|
||||
.current_areas = ~0U,
|
||||
.options = ALLOW_NONE },
|
||||
{ .current_types = SEG_RAID4,
|
||||
.possible_types = SEG_STRIPED_TARGET|SEG_RAID0|SEG_RAID0_META,
|
||||
.current_areas = ~0U,
|
||||
.options = ALLOW_NONE },
|
||||
.options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
|
||||
|
||||
/* END */
|
||||
{ .current_types = 0 }
|
||||
@@ -2861,9 +2894,176 @@ static int _raid1_to_mirrored_wrapper(TAKEOVER_FN_ARGS)
|
||||
allocate_pvs, 1, &removal_lvs);
|
||||
}
|
||||
|
||||
/*
|
||||
* HM Helper: (raid0_meta -> raid4)
|
||||
*
|
||||
* To convert raid0_meta to raid4, which involves shifting the
|
||||
* parity device to lv segment area 0 and thus changing MD
|
||||
* array roles, detach the MetaLVs and reload as raid0 in
|
||||
* order to wipe them then reattach and set back to raid0_meta.
|
||||
*/
|
||||
static int _clear_meta_lvs(struct logical_volume *lv)
|
||||
{
|
||||
uint32_t s;
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
struct lv_segment_area *tmp_areas;
|
||||
const struct segment_type *tmp_segtype;
|
||||
struct dm_list meta_lvs;
|
||||
struct lv_list *lvl_array, *lvl;
|
||||
|
||||
/* Reject non-raid0_meta segment types cautiously */
|
||||
if (!seg_is_raid0_meta(seg) ||
|
||||
!seg->meta_areas)
|
||||
return_0;
|
||||
|
||||
if (!(lvl_array = dm_pool_alloc(lv->vg->vgmem, seg->area_count * sizeof(*lvl_array))))
|
||||
return_0;
|
||||
|
||||
dm_list_init(&meta_lvs);
|
||||
tmp_areas = seg->meta_areas;
|
||||
|
||||
/* Extract all MetaLVs listing them on @meta_lvs */
|
||||
log_debug_metadata("Extracting all MetaLVs of %s to activate as raid0",
|
||||
display_lvname(lv));
|
||||
if (!_extract_image_component_sublist(seg, RAID_META, 0, seg->area_count, &meta_lvs, 0))
|
||||
return_0;
|
||||
|
||||
/* Memorize meta areas and segtype to set again after initializing. */
|
||||
seg->meta_areas = NULL;
|
||||
tmp_segtype = seg->segtype;
|
||||
|
||||
if (!(seg->segtype = get_segtype_from_flag(lv->vg->cmd, SEG_RAID0)) ||
|
||||
!lv_update_and_reload(lv))
|
||||
return_0;
|
||||
|
||||
/*
|
||||
* Now deactivate the MetaLVs before clearing, so
|
||||
* that _clear_lvs() will activate them visible.
|
||||
*/
|
||||
log_debug_metadata("Deactivating pulled out MetaLVs of %s before initializing.",
|
||||
display_lvname(lv));
|
||||
dm_list_iterate_items(lvl, &meta_lvs)
|
||||
if (!deactivate_lv(lv->vg->cmd, lvl->lv))
|
||||
return_0;
|
||||
|
||||
log_debug_metadata("Clearing allocated raid0_meta metadata LVs for conversion to raid4");
|
||||
if (!_clear_lvs(&meta_lvs)) {
|
||||
log_error("Failed to initialize metadata LVs");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set memorized meta areas and raid0_meta segtype */
|
||||
seg->meta_areas = tmp_areas;
|
||||
seg->segtype = tmp_segtype;
|
||||
|
||||
log_debug_metadata("Adding metadata LVs back into %s", display_lvname(lv));
|
||||
s = 0;
|
||||
dm_list_iterate_items(lvl, &meta_lvs) {
|
||||
lv_set_hidden(lvl->lv);
|
||||
if (!set_lv_segment_area_lv(seg, s++, lvl->lv, 0, RAID_META))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* HM Helper: (raid0* <-> raid4)
|
||||
*
|
||||
* Rename SubLVs (pairs) allowing to shift names w/o collisions with active ones.
|
||||
*/
|
||||
#define SLV_COUNT 2
|
||||
static int _rename_area_lvs(struct logical_volume *lv, const char *suffix)
|
||||
{
|
||||
uint32_t s;
|
||||
size_t sz = strlen("rimage") + (suffix ? strlen(suffix) : 0) + 1;
|
||||
char *sfx[SLV_COUNT] = { NULL, NULL };
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
|
||||
/* Create _generate_raid_name() suffixes w/ or w/o passed in @suffix */
|
||||
for (s = 0; s < SLV_COUNT; s++)
|
||||
if (!(sfx[s] = dm_pool_alloc(lv->vg->cmd->mem, sz)) ||
|
||||
dm_snprintf(sfx[s], sz, suffix ? "%s%s" : "%s", s ? "rmeta" : "rimage", suffix) < 0)
|
||||
return_0;
|
||||
|
||||
/* Change names (temporarily) to be able to shift numerical name suffixes */
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (!(seg_lv(seg, s)->name = _generate_raid_name(lv, sfx[0], s)))
|
||||
return_0;
|
||||
if (seg->meta_areas &&
|
||||
!(seg_metalv(seg, s)->name = _generate_raid_name(lv, sfx[1], s)))
|
||||
return_0;
|
||||
}
|
||||
|
||||
for (s = 0; s < SLV_COUNT; s++)
|
||||
dm_pool_free(lv->vg->cmd->mem, sfx[s]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* HM Helper: (raid0* <-> raid4)
|
||||
*
|
||||
* Switch area LVs in lv segment @seg indexed by @s1 and @s2
|
||||
*/
|
||||
static void _switch_area_lvs(struct lv_segment *seg, uint32_t s1, uint32_t s2)
|
||||
{
|
||||
struct logical_volume *lvt;
|
||||
|
||||
lvt = seg_lv(seg, s1);
|
||||
seg_lv(seg, s1) = seg_lv(seg, s2);
|
||||
seg_lv(seg, s2) = lvt;
|
||||
|
||||
/* Be cautious */
|
||||
if (seg->meta_areas) {
|
||||
lvt = seg_metalv(seg, s1);
|
||||
seg_metalv(seg, s1) = seg_metalv(seg, s2);
|
||||
seg_metalv(seg, s2) = lvt;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* HM Helper:
|
||||
*
|
||||
* shift range of area LVs in @seg in range [ @s1, @s2 ] up if @s1 < @s2,
|
||||
* else down bubbling the parity SubLVs up/down whilst shifting.
|
||||
*/
|
||||
static void _shift_area_lvs(struct lv_segment *seg, uint32_t s1, uint32_t s2)
|
||||
{
|
||||
uint32_t s;
|
||||
|
||||
if (s1 < s2)
|
||||
/* Forward shift n+1 -> n */
|
||||
for (s = s1; s < s2; s++)
|
||||
_switch_area_lvs(seg, s, s + 1);
|
||||
else
|
||||
/* Reverse shift n-1 -> n */
|
||||
for (s = s1; s > s2; s--)
|
||||
_switch_area_lvs(seg, s, s - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Switch position of first and last area lv within
|
||||
* @lv to move parity SubLVs from end to end.
|
||||
*
|
||||
* Direction depends on segment type raid4 / raid0_meta.
|
||||
*/
|
||||
static int _shift_parity_dev(struct lv_segment *seg)
|
||||
{
|
||||
if (seg_is_raid0_meta(seg))
|
||||
_shift_area_lvs(seg, seg->area_count - 1, 0);
|
||||
else if (seg_is_raid4(seg))
|
||||
_shift_area_lvs(seg, 0, seg->area_count - 1);
|
||||
else
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* raid45 -> raid0* / striped */
|
||||
static int _raid456_to_raid0_or_striped_wrapper(TAKEOVER_FN_ARGS)
|
||||
{
|
||||
int rename_sublvs = 0;
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
struct dm_list removal_lvs;
|
||||
|
||||
@@ -2879,10 +3079,39 @@ static int _raid456_to_raid0_or_striped_wrapper(TAKEOVER_FN_ARGS)
|
||||
if (!_raid_in_sync(lv))
|
||||
return 0;
|
||||
|
||||
if (!yes && yes_no_prompt("Are you sure you want to convert \"%s\" LV %s to \"%s\" "
|
||||
"type losing all resilience? [y/n]: ",
|
||||
lvseg_name(seg), display_lvname(lv), new_segtype->name) == 'n') {
|
||||
log_error("Logical volume %s NOT converted to \"%s\"",
|
||||
display_lvname(lv), new_segtype->name);
|
||||
return 0;
|
||||
}
|
||||
if (sigint_caught())
|
||||
return_0;
|
||||
|
||||
/* Archive metadata */
|
||||
if (!archive(lv->vg))
|
||||
return_0;
|
||||
|
||||
/*
|
||||
* raid4 (which actually gets mapped to raid5/dedicated first parity disk)
|
||||
* needs shifting of SubLVs to move the parity SubLV pair in the first area
|
||||
* to the last one before conversion to raid0[_meta]/striped to allow for
|
||||
* SubLV removal from the end of the areas arrays.
|
||||
*/
|
||||
if (seg_is_raid4(seg)) {
|
||||
/* Shift parity SubLV pair "PDD..." -> "DD...P" to be able to remove it off the end */
|
||||
if (!_shift_parity_dev(seg))
|
||||
return 0;
|
||||
|
||||
if (segtype_is_any_raid0(new_segtype) &&
|
||||
!(rename_sublvs = _rename_area_lvs(lv, "_"))) {
|
||||
log_error("Failed to rename %s LV %s MetaLVs", lvseg_name(seg), display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Remove meta and data LVs requested */
|
||||
if (!_lv_raid_change_image_count(lv, new_image_count, allocate_pvs, &removal_lvs, 0, 0))
|
||||
return 0;
|
||||
@@ -2902,7 +3131,19 @@ static int _raid456_to_raid0_or_striped_wrapper(TAKEOVER_FN_ARGS)
|
||||
|
||||
seg->region_size = 0;
|
||||
|
||||
return _lv_update_reload_fns_reset_eliminate_lvs(lv, &removal_lvs);
|
||||
if (!_lv_update_reload_fns_reset_eliminate_lvs(lv, &removal_lvs))
|
||||
return_0;
|
||||
|
||||
if (rename_sublvs) {
|
||||
if (!_rename_area_lvs(lv, NULL)) {
|
||||
log_error("Failed to rename %s LV %s MetaLVs", lvseg_name(seg), display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
if (!lv_update_and_reload(lv))
|
||||
return_0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _striped_to_raid0_wrapper(struct logical_volume *lv,
|
||||
@@ -2930,6 +3171,9 @@ static int _striped_to_raid0_wrapper(struct logical_volume *lv,
|
||||
static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS)
|
||||
{
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
struct dm_list removal_lvs;
|
||||
|
||||
dm_list_init(&removal_lvs);
|
||||
|
||||
if (seg_is_raid10(seg))
|
||||
return _takeover_unsupported_yet(lv, new_stripes, new_segtype);
|
||||
@@ -2944,6 +3188,13 @@ static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME: restricted to raid4 for the time being... */
|
||||
if (!segtype_is_raid4(new_segtype)) {
|
||||
/* Can't convert striped/raid0* to e.g. raid10_offset */
|
||||
log_error("Can't convert %s to %s", display_lvname(lv), new_segtype->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Archive metadata */
|
||||
if (!archive(lv->vg))
|
||||
return_0;
|
||||
@@ -2961,7 +3212,10 @@ static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS)
|
||||
log_debug_metadata("Adding metadata LVs to %s", display_lvname(lv));
|
||||
if (!_raid0_add_or_remove_metadata_lvs(lv, 1 /* update_and_reload */, allocate_pvs, NULL))
|
||||
return 0;
|
||||
}
|
||||
/* raid0_meta -> raid4 needs clearing of MetaLVs in order to avoid raid disk role cahnge issues in the kernel */
|
||||
} else if (segtype_is_raid4(new_segtype) &&
|
||||
!_clear_meta_lvs(lv))
|
||||
return 0;
|
||||
|
||||
/* Add the additional component LV pairs */
|
||||
log_debug_metadata("Adding %" PRIu32 " component LV pair(s) to %s", new_image_count - lv_raid_image_count(lv),
|
||||
@@ -2969,8 +3223,9 @@ static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS)
|
||||
if (!_lv_raid_change_image_count(lv, new_image_count, allocate_pvs, NULL, 0, 1))
|
||||
return 0;
|
||||
|
||||
if (!segtype_is_raid4(new_segtype)) {
|
||||
/* Can't convert striped/raid0* to e.g. raid10_offset */
|
||||
if (segtype_is_raid4(new_segtype) &&
|
||||
(!_shift_parity_dev(seg) ||
|
||||
!_rename_area_lvs(lv, "_"))) {
|
||||
log_error("Can't convert %s to %s", display_lvname(lv), new_segtype->name);
|
||||
return 0;
|
||||
}
|
||||
@@ -2987,6 +3242,14 @@ static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS)
|
||||
if (!_lv_update_reload_fns_reset_eliminate_lvs(lv, NULL))
|
||||
return_0;
|
||||
|
||||
if (segtype_is_raid4(new_segtype)) {
|
||||
/* We had to rename SubLVs because of collision free sgifting, rename back... */
|
||||
if (!_rename_area_lvs(lv, NULL))
|
||||
return 0;
|
||||
if (!lv_update_and_reload(lv))
|
||||
return_0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -3630,6 +3893,7 @@ has_enough_space:
|
||||
* new SubLVS are allocated on PVs on list @allocate_pvs.
|
||||
*/
|
||||
static int _lv_raid_rebuild_or_replace(struct logical_volume *lv,
|
||||
int force,
|
||||
struct dm_list *remove_pvs,
|
||||
struct dm_list *allocate_pvs,
|
||||
int rebuild)
|
||||
@@ -3804,7 +4068,8 @@ try_again:
|
||||
* supplied - knowing that only the image with the error target
|
||||
* will be affected.
|
||||
*/
|
||||
if (!_raid_extract_images(lv, raid_seg->area_count - match_count,
|
||||
if (!_raid_extract_images(lv, force,
|
||||
raid_seg->area_count - match_count,
|
||||
partial_segment_removed ?
|
||||
&lv->vg->pvs : remove_pvs, 0,
|
||||
&old_lvs, &old_lvs)) {
|
||||
@@ -3909,7 +4174,7 @@ skip_alloc:
|
||||
int lv_raid_rebuild(struct logical_volume *lv,
|
||||
struct dm_list *rebuild_pvs)
|
||||
{
|
||||
return _lv_raid_rebuild_or_replace(lv, rebuild_pvs, NULL, 1);
|
||||
return _lv_raid_rebuild_or_replace(lv, 0, rebuild_pvs, NULL, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3922,10 +4187,11 @@ int lv_raid_rebuild(struct logical_volume *lv,
|
||||
* allocating new SubLVs from PVs on list @allocate_pvs.
|
||||
*/
|
||||
int lv_raid_replace(struct logical_volume *lv,
|
||||
int force,
|
||||
struct dm_list *remove_pvs,
|
||||
struct dm_list *allocate_pvs)
|
||||
{
|
||||
return _lv_raid_rebuild_or_replace(lv, remove_pvs, allocate_pvs, 0);
|
||||
return _lv_raid_rebuild_or_replace(lv, force, remove_pvs, allocate_pvs, 0);
|
||||
}
|
||||
|
||||
int lv_raid_remove_missing(struct logical_volume *lv)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -268,6 +268,7 @@ struct segment_type *init_unknown_segtype(struct cmd_context *cmd,
|
||||
#define RAID_FEATURE_RAID10 (1U << 0) /* version 1.3 */
|
||||
#define RAID_FEATURE_RAID0 (1U << 1) /* version 1.7 */
|
||||
#define RAID_FEATURE_RESHAPING (1U << 2) /* version 1.8 */
|
||||
#define RAID_FEATURE_RAID4 (1U << 3) /* ! version 1.8 or 1.9.0 */
|
||||
|
||||
#ifdef RAID_INTERNAL
|
||||
int init_raid_segtypes(struct cmd_context *cmd, struct segtype_library *seglib);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2011-2013 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2016 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -366,7 +366,7 @@ static int _raid_target_present(struct cmd_context *cmd,
|
||||
|
||||
static int _raid_checked = 0;
|
||||
static int _raid_present = 0;
|
||||
static int _raid_attrs = 0;
|
||||
static unsigned _raid_attrs = 0;
|
||||
uint32_t maj, min, patchlevel;
|
||||
unsigned i;
|
||||
|
||||
@@ -389,6 +389,12 @@ static int _raid_target_present(struct cmd_context *cmd,
|
||||
else
|
||||
log_very_verbose("Target raid does not support %s.",
|
||||
_features[i].feature);
|
||||
|
||||
if (!(maj == 1 && (min == 8 || (min == 9 && patchlevel == 0))))
|
||||
_raid_attrs |= RAID_FEATURE_RAID4;
|
||||
else
|
||||
log_very_verbose("Target raid does not support %s.",
|
||||
SEG_TYPE_NAME_RAID4);
|
||||
}
|
||||
|
||||
if (attributes)
|
||||
|
@@ -114,9 +114,9 @@ static void _default_log_line(int level,
|
||||
const char *f, va_list ap)
|
||||
{
|
||||
static int _abort_on_internal_errors = -1;
|
||||
FILE *out = (level & _LOG_STDERR) ? stderr : stdout;
|
||||
FILE *out = log_stderr(level) ? stderr : stdout;
|
||||
|
||||
level &= ~(_LOG_STDERR | _LOG_BYPASS_REPORT);
|
||||
level = log_level(level);
|
||||
|
||||
if (level <= _LOG_WARN || _verbose) {
|
||||
if (level < _LOG_WARN)
|
||||
@@ -137,8 +137,7 @@ static void _default_log_line(int level,
|
||||
|
||||
__attribute__((format(printf, 5, 6)))
|
||||
static void _default_log_with_errno(int level,
|
||||
const char *file __attribute__((unused)),
|
||||
int line __attribute__((unused)), int dm_errno_or_class,
|
||||
const char *file, int line, int dm_errno_or_class,
|
||||
const char *f, ...)
|
||||
{
|
||||
va_list ap;
|
||||
@@ -162,29 +161,75 @@ static void _default_log(int level, const char *file,
|
||||
dm_log_fn dm_log = _default_log;
|
||||
dm_log_with_errno_fn dm_log_with_errno = _default_log_with_errno;
|
||||
|
||||
/*
|
||||
* Wrapper function to reformat new messages to and
|
||||
* old style logging which had not used errno parameter
|
||||
*
|
||||
* As we cannot simply pass '...' to old function we
|
||||
* need to process arg list locally and just pass '%s' + buffer
|
||||
*/
|
||||
__attribute__((format(printf, 5, 6)))
|
||||
static void _log_to_default_log(int level,
|
||||
const char *file, int line, int dm_errno_or_class,
|
||||
const char *f, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[2 * PATH_MAX + 256]; /* big enough for most messages */
|
||||
|
||||
va_start(ap, f);
|
||||
vsnprintf(buf, sizeof(buf), f, ap);
|
||||
va_end(ap);
|
||||
|
||||
dm_log(level, file, line, "%s", buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper function take 'old' style message without errno
|
||||
* and log it via new logging function with errno arg
|
||||
*
|
||||
* This minor case may happen if new libdm is used with old
|
||||
* recompiled tool that would decided to use new logging,
|
||||
* but still would like to use old binary plugins.
|
||||
*/
|
||||
__attribute__((format(printf, 4, 5)))
|
||||
static void _log_to_default_log_with_errno(int level,
|
||||
const char *file, int line, const char *f, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[2 * PATH_MAX + 256]; /* big enough for most messages */
|
||||
|
||||
va_start(ap, f);
|
||||
vsnprintf(buf, sizeof(buf), f, ap);
|
||||
va_end(ap);
|
||||
|
||||
dm_log_with_errno(level, file, line, 0, "%s", buf);
|
||||
}
|
||||
|
||||
void dm_log_init(dm_log_fn fn)
|
||||
{
|
||||
if (fn)
|
||||
if (fn) {
|
||||
dm_log = fn;
|
||||
else
|
||||
dm_log_with_errno = _log_to_default_log;
|
||||
} else {
|
||||
dm_log = _default_log;
|
||||
|
||||
dm_log_with_errno = _default_log_with_errno;
|
||||
dm_log_with_errno = _default_log_with_errno;
|
||||
}
|
||||
}
|
||||
|
||||
int dm_log_is_non_default(void)
|
||||
{
|
||||
return (dm_log == _default_log) ? 0 : 1;
|
||||
return (dm_log == _default_log && dm_log_with_errno == _default_log_with_errno) ? 0 : 1;
|
||||
}
|
||||
|
||||
void dm_log_with_errno_init(dm_log_with_errno_fn fn)
|
||||
{
|
||||
if (fn)
|
||||
if (fn) {
|
||||
dm_log = _log_to_default_log_with_errno;
|
||||
dm_log_with_errno = fn;
|
||||
else
|
||||
} else {
|
||||
dm_log = _default_log;
|
||||
dm_log_with_errno = _default_log_with_errno;
|
||||
|
||||
dm_log = _default_log;
|
||||
}
|
||||
}
|
||||
|
||||
void dm_log_init_verbose(int level)
|
||||
|
@@ -3881,7 +3881,7 @@ merge:
|
||||
continue;
|
||||
|
||||
if (_extents_overlap(ext, next)) {
|
||||
log_warn("Warning: region IDs " FMTu64 " and "
|
||||
log_warn("WARNING: region IDs " FMTu64 " and "
|
||||
FMTu64 " overlap. Some events will be "
|
||||
"counted twice.", ext->id, next->id);
|
||||
/* merge larger extent into smaller */
|
||||
@@ -4002,11 +4002,11 @@ int dm_stats_create_group(struct dm_stats *dms, const char *members,
|
||||
}
|
||||
|
||||
if (precise && (precise != count))
|
||||
log_warn("Grouping regions with different clock resolution: "
|
||||
"precision may be lost");
|
||||
log_warn("WARNING: Grouping regions with different clock resolution: "
|
||||
"precision may be lost.");
|
||||
|
||||
if (!_stats_group_check_overlap(dms, regions, count))
|
||||
log_info("Creating group with overlapping regions");
|
||||
log_very_verbose("Creating group with overlapping regions.");
|
||||
|
||||
if (!_stats_create_group(dms, regions, alias, group_id))
|
||||
goto bad;
|
||||
@@ -4048,7 +4048,7 @@ int dm_stats_delete_group(struct dm_stats *dms, uint64_t group_id,
|
||||
if (dm_bit(regions, i)) {
|
||||
dm_bit_clear(regions, i);
|
||||
if (remove_regions && !dm_stats_delete_region(dms, i))
|
||||
log_warn("Failed to delete region "
|
||||
log_warn("WARNING: Failed to delete region "
|
||||
FMTu64 " on %s.", i, dms->name);
|
||||
}
|
||||
}
|
||||
@@ -4142,7 +4142,7 @@ static int _stats_group_file_regions(struct dm_stats *dms, uint64_t *region_ids,
|
||||
* returned by FIEMAP imply a kernel bug or a corrupt fs.
|
||||
*/
|
||||
if (!_stats_group_check_overlap(dms, regions, count))
|
||||
log_info("Creating group with overlapping regions.");
|
||||
log_very_verbose("Creating group with overlapping regions.");
|
||||
|
||||
if (!_stats_create_group(dms, regions, alias, &group_id))
|
||||
goto bad;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -18,16 +18,10 @@
|
||||
|
||||
#include "libdevmapper.h"
|
||||
|
||||
extern dm_log_fn dm_log;
|
||||
extern dm_log_with_errno_fn dm_log_with_errno;
|
||||
|
||||
#define LOG_MESG(l, f, ln, e, x...) \
|
||||
do { \
|
||||
if (dm_log_is_non_default()) \
|
||||
dm_log(l, f, ln, ## x); \
|
||||
else \
|
||||
dm_log_with_errno(l, f, ln, e, ## x); \
|
||||
} while (0)
|
||||
dm_log_with_errno(l, f, ln, e, ## x)
|
||||
|
||||
#define LOG_LINE(l, x...) LOG_MESG(l, __FILE__, __LINE__, 0, ## x)
|
||||
#define LOG_LINE_WITH_ERRNO(l, e, x...) LOG_MESG(l, __FILE__, __LINE__, e, ## x)
|
||||
|
@@ -34,6 +34,7 @@ TOOL=blkdeactivate
|
||||
DEV_DIR='/dev'
|
||||
SYS_BLK_DIR='/sys/block'
|
||||
|
||||
MOUNTPOINT="/bin/mountpoint"
|
||||
UMOUNT="/bin/umount"
|
||||
DMSETUP="@sbindir@/dmsetup"
|
||||
LVM="@sbindir@/lvm"
|
||||
@@ -157,9 +158,11 @@ device_umount_one() {
|
||||
echo -n " [UMOUNT]: unmounting $name ($kname) mounted on $mnt... "
|
||||
if eval $UMOUNT $UMOUNT_OPTS "$(printf "%s" "$mnt")" $OUT $ERR; then
|
||||
echo "done"
|
||||
else
|
||||
elif $MOUNTPOINT -q "$mnt"; then
|
||||
echo "skipping"
|
||||
add_device_to_skip_list
|
||||
else
|
||||
echo "already unmounted"
|
||||
fi
|
||||
else
|
||||
echo " [SKIP]: unmount of $name ($kname) mounted on $mnt"
|
||||
|
@@ -1376,6 +1376,15 @@ have_raid() {
|
||||
esac
|
||||
}
|
||||
|
||||
have_raid4 () {
|
||||
local r=1
|
||||
|
||||
have_raid 1 8 0 && r=0
|
||||
have_raid 1 9 1 && r=1
|
||||
|
||||
return $r
|
||||
}
|
||||
|
||||
have_cache() {
|
||||
test "$CACHE" = shared -o "$CACHE" = internal || {
|
||||
echo "Cache is not built-in." >&2
|
||||
|
@@ -16,7 +16,7 @@ TEST_RAID=raid456
|
||||
aux raid456_replace_works || skip
|
||||
aux have_raid 1 5 2 || skip
|
||||
|
||||
run_types raid4 -i 2 "$dev1" "$dev2" "$dev3" "$dev4"
|
||||
aux have_raid4 && run_types raid4 -i 2 "$dev1" "$dev2" "$dev3" "$dev4"
|
||||
run_types raid5 -i 2 "$dev1" "$dev2" "$dev3" "$dev4"
|
||||
run_types raid6 -i 3 "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
|
||||
|
||||
|
@@ -16,6 +16,9 @@ SKIP_WITH_LVMPOLLD=1
|
||||
|
||||
aux have_raid 1 9 0 || skip
|
||||
|
||||
correct_raid4_layout=0
|
||||
aux have_raid 1 9 1 && correct_raid4_layout=1
|
||||
|
||||
aux prepare_vg 9 288
|
||||
|
||||
# Delay 1st leg so that rebuilding status characters
|
||||
@@ -78,22 +81,61 @@ aux wait_for_sync $vg $lv1
|
||||
# Clean up
|
||||
lvremove --yes $vg/$lv1
|
||||
|
||||
# Create 3-way raid0
|
||||
lvcreate -y -aey --type raid0 -i 3 -L 64M -n $lv1 $vg
|
||||
check lv_field $vg/$lv1 segtype "raid0"
|
||||
# Create 3-way striped
|
||||
lvcreate -y -aey --type striped -i 3 -L 64M -n $lv1 $vg
|
||||
check lv_field $vg/$lv1 segtype "striped"
|
||||
check lv_field $vg/$lv1 stripes 3
|
||||
echo y | mkfs -t ext4 /dev/mapper/$vg-$lv1
|
||||
fsck -fn /dev/mapper/$vg-$lv1
|
||||
|
||||
# Convert raid0 -> raid4
|
||||
# Create 3-way raid0
|
||||
lvcreate -y -aey --type raid0 -i 3 -L 64M -n $lv2 $vg
|
||||
check lv_field $vg/$lv2 segtype "raid0"
|
||||
check lv_field $vg/$lv2 stripes 3
|
||||
echo y | mkfs -t ext4 /dev/mapper/$vg-$lv2
|
||||
fsck -fn /dev/mapper/$vg-$lv2
|
||||
|
||||
# Create 3-way raid0_meta
|
||||
lvcreate -y -aey --type raid0_meta -i 3 -L 64M -n $lv3 $vg
|
||||
check lv_field $vg/$lv3 segtype "raid0_meta"
|
||||
check lv_field $vg/$lv3 stripes 3
|
||||
echo y | mkfs -t ext4 /dev/mapper/$vg-$lv3
|
||||
fsck -fn /dev/mapper/$vg-$lv3
|
||||
|
||||
if [ $correct_raid4_layout -eq 1 ]
|
||||
then
|
||||
|
||||
# Create 3-way raid4
|
||||
lvcreate -y -aey --type raid4 -i 3 -L 64M -n $lv4 $vg
|
||||
check lv_field $vg/$lv4 segtype "raid4"
|
||||
check lv_field $vg/$lv4 stripes 4
|
||||
echo y | mkfs -t ext4 /dev/mapper/$vg-$lv4
|
||||
fsck -fn /dev/mapper/$vg-$lv4
|
||||
aux wait_for_sync $vg $lv4
|
||||
fsck -fn /dev/mapper/$vg-$lv4
|
||||
|
||||
# Convert raid4 -> striped (correct raid4 mapping test!)
|
||||
lvconvert -y --ty striped $vg/$lv4
|
||||
check lv_field $vg/$lv4 segtype "striped"
|
||||
check lv_field $vg/$lv4 stripes 3
|
||||
fsck -fn /dev/mapper/$vg-$lv4
|
||||
|
||||
# Convert striped -> raid4
|
||||
lvconvert -y --ty raid4 $vg/$lv1
|
||||
lvchange --refresh $vg/$lv1
|
||||
check lv_field $vg/$lv1 segtype "raid4"
|
||||
check lv_field $vg/$lv1 stripes 4
|
||||
fsck -fn /dev/mapper/$vg-$lv1
|
||||
aux wait_for_sync $vg $lv1
|
||||
fsck -fn /dev/mapper/$vg-$lv1
|
||||
|
||||
# Convert raid0 -> raid4
|
||||
lvconvert -y --ty raid4 $vg/$lv2
|
||||
check lv_field $vg/$lv2 segtype "raid4"
|
||||
check lv_field $vg/$lv2 stripes 4
|
||||
fsck -fn /dev/mapper/$vg-$lv2
|
||||
aux wait_for_sync $vg $lv2
|
||||
fsck -fn /dev/mapper/$vg-$lv2
|
||||
|
||||
# Convert raid4 -> raid0_meta
|
||||
lvconvert -y --ty raid0_meta $vg/$lv1
|
||||
check lv_field $vg/$lv1 segtype "raid0_meta"
|
||||
@@ -116,11 +158,24 @@ fsck -fn /dev/mapper/$vg-$lv1
|
||||
|
||||
# Convert raid0 -> raid4
|
||||
lvconvert -y --ty raid4 $vg/$lv1
|
||||
lvchange --refresh $vg/$lv1
|
||||
check lv_field $vg/$lv1 segtype "raid4"
|
||||
check lv_field $vg/$lv1 stripes 4
|
||||
fsck -fn /dev/mapper/$vg-$lv1
|
||||
aux wait_for_sync $vg $lv1
|
||||
fsck -fn /dev/mapper/$vg-$lv1
|
||||
|
||||
# Convert raid4 -> striped
|
||||
lvconvert -y --ty striped $vg/$lv1
|
||||
check lv_field $vg/$lv1 segtype "striped"
|
||||
check lv_field $vg/$lv1 stripes 3
|
||||
fsck -fn /dev/mapper/$vg-$lv1
|
||||
|
||||
else
|
||||
|
||||
not lvcreate -y -aey --type raid4 -i 3 -L 64M -n $lv4 $vg
|
||||
not lvconvert -y --ty raid4 $vg/$lv1
|
||||
not lvconvert -y --ty raid4 $vg/$lv2
|
||||
|
||||
fi
|
||||
|
||||
vgremove -ff $vg
|
||||
|
@@ -31,8 +31,11 @@ aux have_raid 1 3 0 || skip
|
||||
aux prepare_pvs 7 # 7 devices for 2 dev replacement of 5-dev RAID6
|
||||
vgcreate -s 256k $vg $(cat DEVICES)
|
||||
|
||||
levels="5 6"
|
||||
aux have_raid4 && levels="4 5 6"
|
||||
|
||||
# RAID 4/5/6 (can replace up to 'parity' devices)
|
||||
for i in 4 5 6; do
|
||||
for i in $levels; do
|
||||
lvcreate --type raid$i -i 3 -l 3 -n $lv1 $vg
|
||||
|
||||
if [ $i -eq 6 ]; then
|
||||
|
@@ -53,7 +53,8 @@ delay 50
|
||||
# RAID1 triple-leg single replace during initial sync
|
||||
lvcreate --type raid1 -m 2 -L $RAID_SIZE -n $lv1 $vg "$dev1" "$dev2" "$dev3"
|
||||
aux disable_dev "$dev2" "$dev3"
|
||||
not lvconvert -y --repair $vg/$lv1
|
||||
# FIXME 2016/11/04 AGK: Disabled next line as it fails to guarantee it is not already in sync.
|
||||
#not lvconvert -y --repair $vg/$lv1
|
||||
aux wait_for_sync $vg $lv1
|
||||
lvconvert -y --repair $vg/$lv1
|
||||
vgreduce --removemissing $vg
|
||||
|
@@ -21,6 +21,9 @@ aux can_use_16T || skip
|
||||
|
||||
aux have_raid 1 3 0 || skip
|
||||
|
||||
segtypes="raid5"
|
||||
aux have_raid4 && segtypes="raid4 raid5"
|
||||
|
||||
# Prepare 5x ~1P sized devices
|
||||
aux prepare_pvs 5 1000000000
|
||||
|
||||
@@ -53,7 +56,7 @@ check raid_leg_status $vg1 $lv1 "AA"
|
||||
lvremove -ff $vg1
|
||||
|
||||
# 750 TiB raid4/5
|
||||
for segtype in raid4 raid5; do
|
||||
for segtype in $segtypes; do
|
||||
lvcreate --type $segtype -i 3 -L 750T -n $lv1 $vg1 --nosync
|
||||
check lv_field $vg1/$lv1 size "750.00t"
|
||||
check raid_leg_status $vg1 $lv1 "AAAA"
|
||||
|
@@ -16,6 +16,9 @@ SKIP_WITH_LVMPOLLD=1
|
||||
|
||||
aux have_raid 1 7 0 || skip
|
||||
|
||||
segtypes=raid5
|
||||
aux have_raid4 && segtypes="raid4 raid5"
|
||||
|
||||
aux prepare_vg 6
|
||||
|
||||
|
||||
@@ -43,7 +46,7 @@ lvcreate --yes --type raid1 --nosync -m 2 -l 1 -n $lv1 $vg
|
||||
check raid_leg_status $vg $lv1 "AAA"
|
||||
lvremove --yes $vg/$lv1
|
||||
|
||||
for r in raid4 raid5
|
||||
for r in $segtypes
|
||||
do
|
||||
# raid4/5 support resynchronization
|
||||
lvcreate --yes --type $r -i 3 -l 2 -n $lv1 $vg
|
||||
|
@@ -23,6 +23,9 @@ lv_devices() {
|
||||
########################################################
|
||||
aux have_raid 1 3 0 || skip
|
||||
|
||||
RAID4=""
|
||||
aux have_raid4 && RAID4=raid4
|
||||
|
||||
aux prepare_pvs 6 20 # 6 devices for RAID10 (2-mirror,3-stripe) test
|
||||
vgcreate -s 512k $vg $(cat DEVICES)
|
||||
|
||||
@@ -54,7 +57,7 @@ aux wait_for_sync $vg $lv1
|
||||
lvremove -ff $vg
|
||||
|
||||
# Create RAID 4/5/6 (explicit 3-stripe + parity devs)
|
||||
for i in raid4 \
|
||||
for i in $RAID4 \
|
||||
raid5 raid5_ls raid5_la raid5_rs raid5_ra \
|
||||
raid6 raid6_zr raid6_nr raid6_nc; do
|
||||
|
||||
@@ -64,7 +67,7 @@ for i in raid4 \
|
||||
done
|
||||
|
||||
# Create RAID 4/5/6 (explicit 3-stripe + parity devs) - Set min/max recovery
|
||||
for i in raid4 \
|
||||
for i in $RAID4 \
|
||||
raid5 raid5_ls raid5_la raid5_rs raid5_ra \
|
||||
raid6 raid6_zr raid6_nr raid6_nc; do
|
||||
|
||||
|
@@ -24,6 +24,28 @@ pvscan --cache
|
||||
|
||||
vgs | grep $vg1
|
||||
|
||||
# Check that an LV cannot be activated by lvchange while VG is exported
|
||||
lvcreate -n $lv1 -l 4 -a n $vg1
|
||||
check lv_exists $vg1
|
||||
vgexport $vg1
|
||||
fail lvs $vg1
|
||||
fail lvchange -ay $vg1/$lv1
|
||||
vgimport $vg1
|
||||
check lv_exists $vg1
|
||||
check lv_field $vg/$lv1 lv_active ""
|
||||
|
||||
# Check that an LV cannot be activated by pvscan while VG is exported
|
||||
vgexport $vg1
|
||||
pvscan --cache -aay "$dev1"
|
||||
pvscan --cache -aay "$dev2"
|
||||
vgimport $vg1
|
||||
check lv_exists $vg1
|
||||
check lv_field $vg1/$lv1 lv_active ""
|
||||
pvscan --cache -aay "$dev1"
|
||||
pvscan --cache -aay "$dev2"
|
||||
check lv_field $vg1/$lv1 lv_active "active"
|
||||
lvchange -an $vg1/$lv1
|
||||
|
||||
# When MDA is ignored on PV, do not read any VG
|
||||
# metadata from such PV as it may contain old
|
||||
# metadata which hasn't been updated for some
|
||||
|
@@ -16,6 +16,9 @@ SKIP_WITH_LVMPOLLD=1
|
||||
|
||||
aux have_raid 1 3 0 || skip
|
||||
|
||||
levels="5 6"
|
||||
aux have_raid4 && levels="4 5 6"
|
||||
|
||||
aux prepare_pvs 6 80
|
||||
|
||||
vgcreate -s 256K $vg $(cat DEVICES)
|
||||
@@ -37,7 +40,7 @@ for deactivate in true false; do
|
||||
#check raid_images_contiguous $vg $lv1
|
||||
|
||||
# Extend and reduce 3-striped RAID 4/5/6
|
||||
for i in 4 5 6 ; do
|
||||
for i in $levels ; do
|
||||
lvcreate --type raid$i -i 3 -l 3 -n $lv2 $vg
|
||||
|
||||
test $deactivate && {
|
||||
@@ -59,7 +62,7 @@ done
|
||||
|
||||
# Bug 1005434
|
||||
# Ensure extend is contiguous
|
||||
lvcreate --type raid4 -l 2 -i 2 -n $lv1 $vg "$dev4" "$dev5" "$dev6"
|
||||
lvcreate --type raid5 -l 2 -i 2 -n $lv1 $vg "$dev4" "$dev5" "$dev6"
|
||||
lvextend -l +2 --alloc contiguous $vg/$lv1
|
||||
check lv_tree_on $vg $lv1 "$dev4" "$dev5" "$dev6"
|
||||
|
||||
|
@@ -1611,7 +1611,7 @@ static int _udevcomplete_all(CMD_ARGS)
|
||||
}
|
||||
|
||||
if (!_switches[YES_ARG]) {
|
||||
log_warn("This operation will destroy all semaphores %s%.0d%swith keys "
|
||||
log_warn("WARNING: This operation will destroy all semaphores %s%.0d%swith keys "
|
||||
"that have a prefix %" PRIu16 " (0x%" PRIx16 ").",
|
||||
age ? "older than " : "", age, age ? " minutes " : "",
|
||||
DM_COOKIE_MAGIC, DM_COOKIE_MAGIC);
|
||||
@@ -2707,6 +2707,9 @@ static int _add_dep(CMD_ARGS)
|
||||
|
||||
/*
|
||||
* Create and walk dependency tree
|
||||
*
|
||||
* An incomplete _dtree may still be used by the caller,
|
||||
* but the error must be reported.
|
||||
*/
|
||||
static int _build_whole_deptree(const struct command *cmd)
|
||||
{
|
||||
@@ -2724,12 +2727,14 @@ static int _build_whole_deptree(const struct command *cmd)
|
||||
|
||||
static int _display_tree(CMD_ARGS)
|
||||
{
|
||||
if (!_build_whole_deptree(cmd))
|
||||
return_0;
|
||||
int r;
|
||||
|
||||
_display_tree_walk_children(dm_tree_find_node(_dtree, 0, 0), 0);
|
||||
r = _build_whole_deptree(cmd);
|
||||
|
||||
return 1;
|
||||
if (_dtree)
|
||||
_display_tree_walk_children(dm_tree_find_node(_dtree, 0, 0), 0);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4471,9 +4476,14 @@ static int _report_init(const struct command *cmd, const char *subcommand)
|
||||
selection, NULL, NULL)))
|
||||
goto_out;
|
||||
|
||||
if ((_report_type & DR_TREE) && cmd && !_build_whole_deptree(cmd)) {
|
||||
err("Internal device dependency tree creation failed.");
|
||||
goto out;
|
||||
r = 1;
|
||||
|
||||
if ((_report_type & DR_TREE) && cmd) {
|
||||
r = _build_whole_deptree(cmd);
|
||||
if (!_dtree) {
|
||||
err("Internal device dependency tree creation failed.");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_switches[INTERVAL_ARG])
|
||||
@@ -4484,8 +4494,6 @@ static int _report_init(const struct command *cmd, const char *subcommand)
|
||||
if (field_prefixes)
|
||||
dm_report_set_output_field_name_prefix(_report, "dm_");
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
if (len)
|
||||
dm_free(options);
|
||||
@@ -5270,6 +5278,8 @@ static int _stats_delete(CMD_ARGS)
|
||||
name = argv[0];
|
||||
}
|
||||
|
||||
if (_switches[PROGRAM_ID_ARG])
|
||||
program_id = _string_args[PROGRAM_ID_ARG];
|
||||
if (_switches[ALL_PROGRAMS_ARG])
|
||||
program_id = DM_STATS_ALL_PROGRAMS;
|
||||
|
||||
@@ -5313,7 +5323,7 @@ static int _stats_delete(CMD_ARGS)
|
||||
log_error("Could not delete statistics region");
|
||||
goto out;
|
||||
}
|
||||
log_info("Deleted statistics region " FMTu64 ".\n", region_id);
|
||||
log_info("Deleted statistics region " FMTu64 ".", region_id);
|
||||
}
|
||||
|
||||
r = 1;
|
||||
@@ -6782,8 +6792,15 @@ unknown:
|
||||
argc--, argv++;
|
||||
}
|
||||
|
||||
if (_switches[COLS_ARG] && !_report_init(cmd, subcommand))
|
||||
goto_out;
|
||||
/* Default to success */
|
||||
ret = 0;
|
||||
|
||||
if (_switches[COLS_ARG]) {
|
||||
if (!_report_init(cmd, subcommand))
|
||||
ret = 1;
|
||||
if (!_report)
|
||||
goto_out;
|
||||
}
|
||||
|
||||
if (_switches[COUNT_ARG])
|
||||
_count = ((uint32_t)_int_args[COUNT_ARG]) ? : UINT32_MAX;
|
||||
@@ -6795,14 +6812,17 @@ unknown:
|
||||
&_disp_units);
|
||||
if (!_disp_factor) {
|
||||
log_error("Invalid --units argument.");
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Start interval timer. */
|
||||
if (_count > 1)
|
||||
if (!_start_timer())
|
||||
if (!_start_timer()) {
|
||||
ret = 1;
|
||||
goto_out;
|
||||
}
|
||||
|
||||
doit:
|
||||
multiple_devices = (cmd->repeatable_cmd && argc != 1 &&
|
||||
@@ -6819,18 +6839,19 @@ doit:
|
||||
if (_count > 1 && r) {
|
||||
printf("\n");
|
||||
/* wait for --interval and update timestamps */
|
||||
if (!_do_report_wait())
|
||||
if (!_do_report_wait()) {
|
||||
ret = 1;
|
||||
goto_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!r)
|
||||
if (!r) {
|
||||
ret = 1;
|
||||
goto_out;
|
||||
}
|
||||
} while (--_count);
|
||||
|
||||
/* Success */
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
if (_report)
|
||||
dm_report_free(_report);
|
||||
|
@@ -1828,6 +1828,25 @@ static void _lvconvert_raid_repair_ask(struct cmd_context *cmd,
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for dm-raid target supporting raid4 conversion properly. */
|
||||
static int _raid4_conversion_supported(struct logical_volume *lv, struct lvconvert_params *lp)
|
||||
{
|
||||
int ret = 1;
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
|
||||
if (seg_is_raid4(seg))
|
||||
ret = raid4_is_supported(lv->vg->cmd, seg->segtype);
|
||||
else if (segtype_is_raid4(lp->segtype))
|
||||
ret = raid4_is_supported(lv->vg->cmd, lp->segtype);
|
||||
|
||||
if (ret)
|
||||
return 1;
|
||||
|
||||
log_error("Cannot convert %s LV %s to %s.",
|
||||
lvseg_name(seg), display_lvname(lv), lp->segtype->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *lp)
|
||||
{
|
||||
int replace = 0, image_count = 0;
|
||||
@@ -1944,13 +1963,24 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
|
||||
|
||||
if ((seg_is_linear(seg) || seg_is_striped(seg) || seg_is_mirrored(seg) || lv_is_raid(lv)) &&
|
||||
(lp->type_str && lp->type_str[0])) {
|
||||
/* Activation is required later which precludes existing unsupported raid0 segment */
|
||||
if (segtype_is_any_raid0(lp->segtype) &&
|
||||
/* Activation is required later which precludes existing supported raid0 segment */
|
||||
if ((seg_is_any_raid0(seg) || segtype_is_any_raid0(lp->segtype)) &&
|
||||
!(lp->target_attr & RAID_FEATURE_RAID0)) {
|
||||
log_error("RAID module does not support RAID0.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Activation is required later which precludes existing supported raid4 segment */
|
||||
if (!_raid4_conversion_supported(lv, lp))
|
||||
return 0;
|
||||
|
||||
/* Activation is required later which precludes existing supported raid10 segment */
|
||||
if ((seg_is_raid10(seg) || segtype_is_raid10(lp->segtype)) &&
|
||||
!(lp->target_attr & RAID_FEATURE_RAID10)) {
|
||||
log_error("RAID module does not support RAID10.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!arg_is_set(cmd, stripes_long_ARG))
|
||||
lp->stripes = 0;
|
||||
|
||||
@@ -1964,7 +1994,7 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
|
||||
}
|
||||
|
||||
if (lp->replace)
|
||||
return lv_raid_replace(lv, lp->replace_pvh, lp->pvh);
|
||||
return lv_raid_replace(lv, lp->force, lp->replace_pvh, lp->pvh);
|
||||
|
||||
if (lp->repair) {
|
||||
if (!lv_is_active_exclusive_locally(lv_lock_holder(lv))) {
|
||||
@@ -1987,7 +2017,7 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
|
||||
if (!(failed_pvs = _failed_pv_list(lv->vg)))
|
||||
return_0;
|
||||
|
||||
if (!lv_raid_replace(lv, failed_pvs, lp->pvh)) {
|
||||
if (!lv_raid_replace(lv, lp->force, failed_pvs, lp->pvh)) {
|
||||
log_error("Failed to replace faulty devices in %s.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
@@ -2008,6 +2038,9 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
|
||||
|
||||
try_new_takeover_or_reshape:
|
||||
|
||||
if (!_raid4_conversion_supported(lv, lp))
|
||||
return 0;
|
||||
|
||||
/* FIXME This needs changing globally. */
|
||||
if (!arg_is_set(cmd, stripes_long_ARG))
|
||||
lp->stripes = 0;
|
||||
|
@@ -1054,6 +1054,12 @@ static int _lvcreate_params(struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (segtype_is_raid4(lp->segtype) &&
|
||||
!(lp->target_attr & RAID_FEATURE_RAID4)) {
|
||||
log_error("RAID module does not support RAID4.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (segtype_is_raid10(lp->segtype) && !(lp->target_attr & RAID_FEATURE_RAID10)) {
|
||||
log_error("RAID module does not support RAID10.");
|
||||
return 0;
|
||||
|
@@ -194,6 +194,9 @@ static int _pvscan_autoactivate_single(struct cmd_context *cmd, const char *vg_n
|
||||
if (vg_is_clustered(vg))
|
||||
return ECMD_PROCESSED;
|
||||
|
||||
if (vg_is_exported(vg))
|
||||
return ECMD_PROCESSED;
|
||||
|
||||
if (is_lockd_type(vg->lock_type))
|
||||
return ECMD_PROCESSED;
|
||||
|
||||
|
Reference in New Issue
Block a user