master - lvmdbusd: Use udev until ExternalEvent occurs
by tasleson
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=4902034c895d26...
Commit: 4902034c895d26423564175c0636cff8ba4112e1
Parent: 2352ff24a55757a70869f443126d67cece0fb0a4
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Wed Aug 24 18:29:35 2016 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Mon Aug 29 15:26:55 2016 -0500
lvmdbusd: Use udev until ExternalEvent occurs
The normal mode of operation will be to monitor for udev events until an
ExternalEvent occurs. In that case the service will disable monitoring
for udev events and use ExternalEvent exclusively.
Note: User specifies --udev the service will always monitor udev regardless
if ExternalEvent is being called too.
---
daemons/lvmdbusd/cfg.py | 14 +++++++++-----
daemons/lvmdbusd/cmdhandler.py | 24 ++++++++++++++++++------
daemons/lvmdbusd/lvm_shell_proxy.py | 6 ++++++
daemons/lvmdbusd/main.py | 28 ++++++++++++++--------------
daemons/lvmdbusd/manager.py | 9 ++++++++-
daemons/lvmdbusd/udevwatch.py | 25 ++++++++++++++++---------
daemons/lvmdbusd/utils.py | 2 +-
7 files changed, 72 insertions(+), 36 deletions(-)
diff --git a/daemons/lvmdbusd/cfg.py b/daemons/lvmdbusd/cfg.py
index 8aec8ae..1d773c3 100644
--- a/daemons/lvmdbusd/cfg.py
+++ b/daemons/lvmdbusd/cfg.py
@@ -24,14 +24,18 @@ om = None
# This is the global bus connection
bus = None
+# Command line args
+args = None
+
+# Set to true if we are depending on external events for updates
+ee = False
+
# Shared state variable across all processes
run = multiprocessing.Value('i', 1)
-# Debug
-DEBUG = True
-
-# Use lvm shell
-USE_SHELL = False
+# If this is set to true, the current setup support lvm shell and we are
+# running in that mode of operation
+SHELL_IN_USE = None
# Lock used by pprint
stdout_lock = multiprocessing.Lock()
diff --git a/daemons/lvmdbusd/cmdhandler.py b/daemons/lvmdbusd/cmdhandler.py
index 0d35782..5815031 100644
--- a/daemons/lvmdbusd/cmdhandler.py
+++ b/daemons/lvmdbusd/cmdhandler.py
@@ -13,6 +13,7 @@ import threading
from itertools import chain
import collections
import traceback
+import os
try:
from . import cfg
@@ -101,7 +102,8 @@ def call_lvm(command, debug=False):
# in different locations on the same box
command.insert(0, cfg.LVM_CMD)
- process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True)
+ process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True,
+ env=os.environ)
out = process.communicate()
stdout_text = bytes(out[0]).decode("utf-8")
@@ -111,7 +113,7 @@ def call_lvm(command, debug=False):
_debug_c(command, process.returncode, (stdout_text, stderr_text))
if process.returncode == 0:
- if cfg.DEBUG and out[1] and len(out[1]) and 'help' not in command:
+ if cfg.args.debug and out[1] and len(out[1]) and 'help' not in command:
log_error('WARNING: lvm is out-putting text to STDERR on success!')
_debug_c(command, process.returncode, (stdout_text, stderr_text))
@@ -123,9 +125,10 @@ def _shell_cfg():
try:
lvm_shell = LVMShellProxy()
_t_call = lvm_shell.call_lvm
- cfg.USE_SHELL = True
+ cfg.SHELL_IN_USE = lvm_shell
except Exception:
_t_call = call_lvm
+ cfg.SHELL_IN_USE = None
log_error(traceback.format_exc())
log_error("Unable to utilize lvm shell, dropping back to fork & exec")
@@ -133,6 +136,15 @@ def _shell_cfg():
def set_execution(shell):
global _t_call
with cmd_lock:
+ # If the user requested lvm shell and we are currently setup that
+ # way, just return
+ if cfg.SHELL_IN_USE and shell:
+ return
+ else:
+ if not shell and cfg.SHELL_IN_USE:
+ cfg.SHELL_IN_USE.exit_shell()
+ cfg.SHELL_IN_USE = None
+
_t_call = call_lvm
if shell:
_shell_cfg()
@@ -217,7 +229,7 @@ def pv_remove(device, remove_options):
def _qt(tag_name):
# When running in lvm shell you need to quote the tags
- if cfg.USE_SHELL:
+ if cfg.SHELL_IN_USE:
return '"%s"' % tag_name
return tag_name
@@ -440,7 +452,7 @@ def supports_json():
cmd = ['help']
rc, out, err = call(cmd)
if rc == 0:
- if cfg.USE_SHELL:
+ if cfg.SHELL_IN_USE:
return True
else:
if 'fullreport' in err:
@@ -488,7 +500,7 @@ def lvm_full_report_json():
# With the current implementation, if we are using the shell then we
# are using JSON and JSON is returned back to us as it was parsed to
# figure out if we completed OK or not
- if cfg.USE_SHELL:
+ if cfg.SHELL_IN_USE:
assert(type(out) == dict)
return out
else:
diff --git a/daemons/lvmdbusd/lvm_shell_proxy.py b/daemons/lvmdbusd/lvm_shell_proxy.py
index d4eff86..3455342 100755
--- a/daemons/lvmdbusd/lvm_shell_proxy.py
+++ b/daemons/lvmdbusd/lvm_shell_proxy.py
@@ -203,6 +203,12 @@ class LVMShellProxy(object):
return rc, json_result, error_msg
+ def exit_shell(self):
+ try:
+ self._write_cmd('exit\n')
+ except Exception as e:
+ log_error(str(e))
+
def __del__(self):
try:
self.lvm_shell.terminate()
diff --git a/daemons/lvmdbusd/main.py b/daemons/lvmdbusd/main.py
index 638323a..d76b5c3 100644
--- a/daemons/lvmdbusd/main.py
+++ b/daemons/lvmdbusd/main.py
@@ -92,6 +92,7 @@ def process_request():
def main():
+ start = time.time()
# Add simple command line handling
parser = argparse.ArgumentParser()
parser.add_argument("--udev", action='store_true',
@@ -112,16 +113,13 @@ def main():
# Ensure that we get consistent output for parsing stdout/stderr
os.environ["LC_ALL"] = "C"
- args = parser.parse_args()
+ cfg.args = parser.parse_args()
- cfg.DEBUG = args.debug
- cmdhandler.set_execution(args.use_lvm_shell)
+ cmdhandler.set_execution(cfg.args.use_lvm_shell)
# List of threads that we start up
thread_list = []
- start = time.time()
-
# Install signal handlers
for s in [signal.SIGHUP, signal.SIGINT]:
try:
@@ -144,7 +142,7 @@ def main():
cfg.load = load
- cfg.db = lvmdb.DataStore(args.use_json)
+ cfg.db = lvmdb.DataStore(cfg.args.use_json)
# Start up thread to monitor pv moves
thread_list.append(
@@ -160,23 +158,25 @@ def main():
process.damon = True
process.start()
+ # Add udev watching
+ if cfg.args.use_udev:
+ log_debug('Utilizing udev to trigger updates')
+
+ # In all cases we are going to monitor for udev until we get an
+ # ExternalEvent. In the case where we get an external event and the user
+ # didn't specify --udev we will stop monitoring udev
+ udevwatch.add()
+
end = time.time()
log_debug(
'Service ready! total time= %.4f, lvm time= %.4f count= %d' %
(end - start, cmdhandler.total_time, cmdhandler.total_count),
'bg_black', 'fg_light_green')
- # Add udev watching
- if args.use_udev:
- log_debug('Utilizing udev to trigger updates')
- udevwatch.add()
-
try:
if cfg.run.value != 0:
cfg.loop.run()
-
- if args.use_udev:
- udevwatch.remove()
+ udevwatch.remove()
for process in thread_list:
process.join()
diff --git a/daemons/lvmdbusd/manager.py b/daemons/lvmdbusd/manager.py
index 2388d8a..79254fe 100644
--- a/daemons/lvmdbusd/manager.py
+++ b/daemons/lvmdbusd/manager.py
@@ -17,7 +17,7 @@ from . import cmdhandler
from .fetch import load_pvs, load_vgs
from .request import RequestEntry
from .refresh import event_add
-
+from . import udevwatch
# noinspection PyPep8Naming
class Manager(AutomatedProperties):
@@ -181,6 +181,13 @@ class Manager(AutomatedProperties):
in_signature='s', out_signature='i')
def ExternalEvent(self, command):
+ # If a user didn't explicitly specify udev, we will turn it off now.
+ if not cfg.args.use_udev:
+ if udevwatch.remove():
+ utils.log_debug("ExternalEvent received, disabling "
+ "udev monitoring")
+ # We are dependent on external events now to stay current!
+ cfg.ee = True
event_add((command,))
return dbus.Int32(0)
diff --git a/daemons/lvmdbusd/udevwatch.py b/daemons/lvmdbusd/udevwatch.py
index c3e6e60..6d56443 100644
--- a/daemons/lvmdbusd/udevwatch.py
+++ b/daemons/lvmdbusd/udevwatch.py
@@ -8,10 +8,12 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import pyudev
+import threading
from .refresh import event_add
from . import cfg
observer = None
+observer_lock = threading.RLock()
# noinspection PyUnusedLocal
@@ -40,15 +42,20 @@ def filter_event(action, device):
def add():
- global observer
- context = pyudev.Context()
- monitor = pyudev.Monitor.from_netlink(context)
- monitor.filter_by('block')
- observer = pyudev.MonitorObserver(monitor, filter_event)
- observer.start()
+ with observer_lock:
+ global observer
+ context = pyudev.Context()
+ monitor = pyudev.Monitor.from_netlink(context)
+ monitor.filter_by('block')
+ observer = pyudev.MonitorObserver(monitor, filter_event)
+ observer.start()
def remove():
- global observer
- observer.stop()
- observer = None
+ with observer_lock:
+ global observer
+ if observer:
+ observer.stop()
+ observer = None
+ return True
+ return False
diff --git a/daemons/lvmdbusd/utils.py b/daemons/lvmdbusd/utils.py
index 9db7857..65668fc 100644
--- a/daemons/lvmdbusd/utils.py
+++ b/daemons/lvmdbusd/utils.py
@@ -265,7 +265,7 @@ def _common_log(msg, *attributes):
# @param msg Message to output to stdout
# @return None
def log_debug(msg, *attributes):
- if cfg.DEBUG:
+ if cfg.args.debug:
_common_log(msg, *attributes)
7 years, 3 months
master - lvmdbusd: Add support for using lvm shell
by tasleson
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=2352ff24a55757...
Commit: 2352ff24a55757a70869f443126d67cece0fb0a4
Parent: a0a2c84a26a9542d32fa7db1f7dcae8ccb8beb88
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Fri Aug 12 15:23:05 2016 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Mon Aug 29 15:26:55 2016 -0500
lvmdbusd: Add support for using lvm shell
With the addition of JSON and the ability to get output which is known to
not contain any extraneous text we can now leverage lvm shell, so that we
don't fork and exec lvm command line repeatedly.
---
daemons/lvmdbusd/cmdhandler.py | 53 ++++++---
daemons/lvmdbusd/lvm_shell_proxy.py | 224 +++++++++++++++++++++-------------
daemons/lvmdbusd/main.py | 7 +-
3 files changed, 177 insertions(+), 107 deletions(-)
diff --git a/daemons/lvmdbusd/cmdhandler.py b/daemons/lvmdbusd/cmdhandler.py
index fac582c..0d35782 100644
--- a/daemons/lvmdbusd/cmdhandler.py
+++ b/daemons/lvmdbusd/cmdhandler.py
@@ -12,6 +12,7 @@ import time
import threading
from itertools import chain
import collections
+import traceback
try:
from . import cfg
@@ -119,27 +120,22 @@ def call_lvm(command, debug=False):
def _shell_cfg():
global _t_call
- log_debug('Using lvm shell!')
- lvm_shell = LVMShellProxy()
- _t_call = lvm_shell.call_lvm
-
-
-if cfg.USE_SHELL:
- _shell_cfg()
-else:
- _t_call = call_lvm
+ try:
+ lvm_shell = LVMShellProxy()
+ _t_call = lvm_shell.call_lvm
+ cfg.USE_SHELL = True
+ except Exception:
+ _t_call = call_lvm
+ log_error(traceback.format_exc())
+ log_error("Unable to utilize lvm shell, dropping back to fork & exec")
def set_execution(shell):
global _t_call
with cmd_lock:
- _t_call = None
+ _t_call = call_lvm
if shell:
- log_debug('Using lvm shell!')
- lvm_shell = LVMShellProxy()
- _t_call = lvm_shell.call_lvm
- else:
- _t_call = call_lvm
+ _shell_cfg()
def time_wrapper(command, debug=False):
@@ -219,6 +215,13 @@ def pv_remove(device, remove_options):
return call(cmd)
+def _qt(tag_name):
+ # When running in lvm shell you need to quote the tags
+ if cfg.USE_SHELL:
+ return '"%s"' % tag_name
+ return tag_name
+
+
def _tag(operation, what, add, rm, tag_options):
cmd = [operation]
cmd.extend(options_to_cli_args(tag_options))
@@ -229,9 +232,11 @@ def _tag(operation, what, add, rm, tag_options):
cmd.append(what)
if add:
- cmd.extend(list(chain.from_iterable(('--addtag', x) for x in add)))
+ cmd.extend(list(chain.from_iterable(
+ ('--addtag', _qt(x)) for x in add)))
if rm:
- cmd.extend(list(chain.from_iterable(('--deltag', x) for x in rm)))
+ cmd.extend(list(chain.from_iterable(
+ ('--deltag', _qt(x)) for x in rm)))
return call(cmd, False)
@@ -435,8 +440,11 @@ def supports_json():
cmd = ['help']
rc, out, err = call(cmd)
if rc == 0:
- if 'fullreport' in err:
+ if cfg.USE_SHELL:
return True
+ else:
+ if 'fullreport' in err:
+ return True
return False
@@ -477,7 +485,14 @@ def lvm_full_report_json():
rc, out, err = call(cmd)
if rc == 0:
- return json.loads(out)
+ # With the current implementation, if we are using the shell then we
+ # are using JSON and JSON is returned back to us as it was parsed to
+ # figure out if we completed OK or not
+ if cfg.USE_SHELL:
+ assert(type(out) == dict)
+ return out
+ else:
+ return json.loads(out)
return None
diff --git a/daemons/lvmdbusd/lvm_shell_proxy.py b/daemons/lvmdbusd/lvm_shell_proxy.py
index 3835c74..d4eff86 100755
--- a/daemons/lvmdbusd/lvm_shell_proxy.py
+++ b/daemons/lvmdbusd/lvm_shell_proxy.py
@@ -14,10 +14,20 @@
import subprocess
import shlex
from fcntl import fcntl, F_GETFL, F_SETFL
-from os import O_NONBLOCK
+import os
import traceback
import sys
-import re
+import tempfile
+import time
+import select
+import copy
+
+try:
+ from simplejson.scanner import JSONDecodeError
+ import simplejson as json
+except ImportError:
+ import json
+
try:
from .cfg import LVM_CMD
@@ -38,42 +48,52 @@ def _quote_arg(arg):
class LVMShellProxy(object):
def _read_until_prompt(self):
- prev_ec = None
stdout = ""
- while not stdout.endswith(SHELL_PROMPT):
- try:
- tmp = self.lvm_shell.stdout.read()
- if tmp:
- stdout += tmp.decode("utf-8")
- except IOError:
- # nothing written yet
- pass
-
- # strip the prompt from the STDOUT before returning and grab the exit
- # code if it's available
- m = self.re.match(stdout)
- if m:
- prev_ec = int(m.group(2))
- strip_idx = -1 * len(m.group(1))
- else:
- strip_idx = -1 * len(SHELL_PROMPT)
-
- return stdout[:strip_idx], prev_ec
+ report = ""
+ stderr = ""
- def _read_line(self):
- while True:
+ # Try reading from all FDs to prevent one from filling up and causing
+ # a hang. We are also assuming that we won't get the lvm prompt back
+ # until we have already received all the output from stderr and the
+ # report descriptor too.
+ while not stdout.endswith(SHELL_PROMPT):
try:
- tmp = self.lvm_shell.stdout.readline()
- if tmp:
- return tmp.decode("utf-8")
- except IOError:
+ rd_fd = [
+ self.lvm_shell.stdout.fileno(),
+ self.report_r,
+ self.lvm_shell.stderr.fileno()]
+ ready = select.select(rd_fd, [], [], 2)
+
+ for r in ready[0]:
+ if r == self.lvm_shell.stdout.fileno():
+ while True:
+ tmp = self.lvm_shell.stdout.read()
+ if tmp:
+ stdout += tmp.decode("utf-8")
+ else:
+ break
+
+ elif r == self.report_r:
+ while True:
+ tmp = os.read(self.report_r, 16384)
+ if tmp:
+ report += tmp.decode("utf-8")
+ if len(tmp) != 16384:
+ break
+
+ elif r == self.lvm_shell.stderr.fileno():
+ while True:
+ tmp = self.lvm_shell.stderr.read()
+ if tmp:
+ stderr += tmp.decode("utf-8")
+ else:
+ break
+
+ except IOError as ioe:
+ log_debug(str(ioe))
pass
- def _discard_echo(self, expected):
- line = ""
- while line != expected:
- # GNU readline inserts some interesting characters at times...
- line += self._read_line().replace(' \r', '')
+ return stdout, report, stderr
def _write_cmd(self, cmd):
cmd_bytes = bytes(cmd, "utf-8")
@@ -81,39 +101,82 @@ class LVMShellProxy(object):
assert (num_written == len(cmd_bytes))
self.lvm_shell.stdin.flush()
- def _lvm_echos(self):
- echo = False
- cmd = "version\n"
- self._write_cmd(cmd)
- line = self._read_line()
+ def __init__(self):
- if line == cmd:
- echo = True
+ # Create a temp directory
+ tmp_dir = tempfile.mkdtemp(prefix="lvmdbus_")
+ tmp_file = "%s/lvmdbus_report" % (tmp_dir)
- self._read_until_prompt()
+ try:
+ # Lets create fifo for the report output
+ os.mkfifo(tmp_file, 0o600)
+ except FileExistsError:
+ pass
- return echo
+ self.report_r = os.open(tmp_file, os.O_NONBLOCK)
+
+ # Setup the environment for using our own socket for reporting
+ local_env = copy.deepcopy(os.environ)
+ local_env["LVM_REPORT_FD"] = "32"
+ local_env["LVM_COMMAND_PROFILE"] = "lvmdbusd"
- def __init__(self):
- self.re = re.compile(".*(\[(-?[0-9]+)\] lvm> $)", re.DOTALL)
+
+ flags = fcntl(self.report_r, F_GETFL)
+ fcntl(self.report_r, F_SETFL, flags | os.O_NONBLOCK)
# run the lvm shell
self.lvm_shell = subprocess.Popen(
- [LVM_CMD], stdin=subprocess.PIPE, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE, close_fds=True)
+ [LVM_CMD + " 32>%s" % tmp_file],
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE, env=local_env,
+ stderr=subprocess.PIPE, close_fds=True, shell=True)
flags = fcntl(self.lvm_shell.stdout, F_GETFL)
- fcntl(self.lvm_shell.stdout, F_SETFL, flags | O_NONBLOCK)
+ fcntl(self.lvm_shell.stdout, F_SETFL, flags | os.O_NONBLOCK)
flags = fcntl(self.lvm_shell.stderr, F_GETFL)
- fcntl(self.lvm_shell.stderr, F_SETFL, flags | O_NONBLOCK)
+ fcntl(self.lvm_shell.stderr, F_SETFL, flags | os.O_NONBLOCK)
# wait for the first prompt
- self._read_until_prompt()
+ errors = self._read_until_prompt()[2]
+ if errors and len(errors):
+ raise RuntimeError(errors)
+
+ # These will get deleted when the FD count goes to zero so we can be
+ # sure to clean up correctly no matter how we finish
+ os.unlink(tmp_file)
+ os.rmdir(tmp_dir)
+
+ def get_error_msg(self):
+ # We got an error, lets go fetch the error message
+ self._write_cmd('lastlog\n')
+
+ # read everything from the STDOUT to the next prompt
+ stdout, report, stderr = self._read_until_prompt()
- # Check to see if the version of LVM we are using is running with
- # gnu readline which will echo our writes from stdin to stdout
- self.echo = self._lvm_echos()
+ try:
+ log = json.loads(report)
+
+ if 'log' in log:
+ error_msg = ""
+ # Walk the entire log array and build an error string
+ for log_entry in log['log']:
+ if log_entry['log_type'] == "error":
+ if error_msg:
+ error_msg += ', ' + log_entry['log_message']
+ else:
+ error_msg = log_entry['log_message']
+
+ return error_msg
+
+ return 'No error reason provided! (missing "log" section)'
+ except ValueError:
+ log_error("Invalid JSON returned from LVM")
+ log_error("BEGIN>>\n%s\n<<END" % report)
+ return "Invalid JSON returned from LVM when retrieving exit code"
def call_lvm(self, argv, debug=False):
+ rc = 1
+ error_msg = ""
+ json_result = ""
+
# create the command string
cmd = " ".join(_quote_arg(arg) for arg in argv)
cmd += "\n"
@@ -121,46 +184,30 @@ class LVMShellProxy(object):
# run the command by writing it to the shell's STDIN
self._write_cmd(cmd)
- # If lvm is utilizing gnu readline, it echos stdin to stdout
- if self.echo:
- self._discard_echo(cmd)
-
# read everything from the STDOUT to the next prompt
- stdout, exit_code = self._read_until_prompt()
+ stdout, report, stderr = self._read_until_prompt()
- # read everything from STDERR if there's something (we waited for the
- # prompt on STDOUT so there should be all or nothing at this point on
- # STDERR)
- stderr = None
- try:
- t_error = self.lvm_shell.stderr.read()
- if t_error:
- stderr = t_error.decode("utf-8")
- except IOError:
- # nothing on STDERR
- pass
-
- if exit_code is not None:
- rc = exit_code
- else:
- # LVM does write to stderr even when it did complete successfully,
- # so without having the exit code in the prompt we can never be
- # sure.
- if stderr:
- rc = 1
- else:
- rc = 0
+ # Parse the report to see what happened
+ if report and len(report):
+ json_result = json.loads(report)
+ if 'log' in json_result:
+ if json_result['log'][-1:][0]['log_ret_code'] == '1':
+ rc = 0
+ else:
+ error_msg = self.get_error_msg()
if debug or rc != 0:
log_error(('CMD: %s' % cmd))
log_error(("EC = %d" % rc))
- log_error(("STDOUT=\n %s\n" % stdout))
- log_error(("STDERR=\n %s\n" % stderr))
+ log_error(("ERROR_MSG=\n %s\n" % error_msg))
- return (rc, stdout, stderr)
+ return rc, json_result, error_msg
def __del__(self):
- self.lvm_shell.terminate()
+ try:
+ self.lvm_shell.terminate()
+ except:
+ pass
if __name__ == "__main__":
@@ -170,10 +217,15 @@ if __name__ == "__main__":
while in_line:
in_line = input("lvm> ")
if in_line:
- ret, out, err, = shell.call_lvm(in_line.split())
- print(("RET: %d" % ret))
- print(("OUT:\n%s" % out))
+ start = time.time()
+ ret, out, err = shell.call_lvm(in_line.split())
+ end = time.time()
+
+ print(("RC: %d" % ret))
+ #print(("OUT:\n%s" % out))
print(("ERR:\n%s" % err))
+
+ print("Command = %f seconds" % (end - start))
except KeyboardInterrupt:
pass
except EOFError:
diff --git a/daemons/lvmdbusd/main.py b/daemons/lvmdbusd/main.py
index f28b402..638323a 100644
--- a/daemons/lvmdbusd/main.py
+++ b/daemons/lvmdbusd/main.py
@@ -100,10 +100,12 @@ def main():
parser.add_argument("--debug", action='store_true',
help="Dump debug messages", default=False,
dest='debug')
-
parser.add_argument("--nojson", action='store_false',
help="Do not use LVM JSON output", default=None,
dest='use_json')
+ parser.add_argument("--lvmshell", action='store_true',
+ help="Use the lvm shell, not fork & exec lvm", default=False,
+ dest='use_lvm_shell')
use_session = os.getenv('LVMDBUSD_USE_SESSION', False)
@@ -113,6 +115,7 @@ def main():
args = parser.parse_args()
cfg.DEBUG = args.debug
+ cmdhandler.set_execution(args.use_lvm_shell)
# List of threads that we start up
thread_list = []
@@ -159,7 +162,7 @@ def main():
end = time.time()
log_debug(
- 'Service ready! total time= %.2f, lvm time= %.2f count= %d' %
+ 'Service ready! total time= %.4f, lvm time= %.4f count= %d' %
(end - start, cmdhandler.total_time, cmdhandler.total_count),
'bg_black', 'fg_light_green')
7 years, 3 months
master - lvmdbusd: Add date & ts if running in a terminal
by tasleson
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=a0a2c84a26a954...
Commit: a0a2c84a26a9542d32fa7db1f7dcae8ccb8beb88
Parent: 7e37e7fde4e683572fa3d9a640821ba9bd4bb3d0
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Fri Aug 12 15:20:49 2016 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Mon Aug 29 15:26:55 2016 -0500
lvmdbusd: Add date & ts if running in a terminal
When we are running in a terminal it's useful to have a date & ts on log
output like you get when output goes to the journal. Check if we are
running on a tty and if we are, add it in.
---
daemons/lvmdbusd/utils.py | 9 ++++++++-
1 files changed, 8 insertions(+), 1 deletions(-)
diff --git a/daemons/lvmdbusd/utils.py b/daemons/lvmdbusd/utils.py
index 3dcb373..9db7857 100644
--- a/daemons/lvmdbusd/utils.py
+++ b/daemons/lvmdbusd/utils.py
@@ -13,6 +13,7 @@ import inspect
import ctypes
import os
import string
+import datetime
import dbus
import dbus.service
@@ -243,7 +244,13 @@ def _common_log(msg, *attributes):
cfg.stdout_lock.acquire()
tid = ctypes.CDLL('libc.so.6').syscall(186)
- msg = "%d:%d - %s" % (os.getpid(), tid, msg)
+ if STDOUT_TTY:
+ msg = "%s: %d:%d - %s" % \
+ (datetime.datetime.now().strftime("%b %d %H:%M:%S.%f"),
+ os.getpid(), tid, msg)
+
+ else:
+ msg = "%d:%d - %s" % (os.getpid(), tid, msg)
if STDOUT_TTY and attributes:
print(color(msg, *attributes))
7 years, 3 months
master - lvmdbusd: Always fork & exec background commands
by tasleson
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=7e37e7fde4e683...
Commit: 7e37e7fde4e683572fa3d9a640821ba9bd4bb3d0
Parent: 784b46ef2a3b674def64a1185733122b300bb22c
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Fri Aug 12 15:19:03 2016 -0500
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Mon Aug 29 15:26:55 2016 -0500
lvmdbusd: Always fork & exec background commands
Our background job support requires a separate instance of lvm. Use the
full lvm command to do so.
---
daemons/lvmdbusd/background.py | 13 +++++++++++++
1 files changed, 13 insertions(+), 0 deletions(-)
diff --git a/daemons/lvmdbusd/background.py b/daemons/lvmdbusd/background.py
index 8078b66..0c0b509 100644
--- a/daemons/lvmdbusd/background.py
+++ b/daemons/lvmdbusd/background.py
@@ -15,6 +15,7 @@ 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()
@@ -130,8 +131,16 @@ def background_execute(command, background_job):
# 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")
@@ -150,8 +159,12 @@ def background_execute(command, background_job):
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
7 years, 3 months
master - debug: better verbose message
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=784b46ef2a3b67...
Commit: 784b46ef2a3b674def64a1185733122b300bb22c
Parent: 92d5a8441007f578e000b492cecf67d6b8a87405
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Mon Aug 29 13:38:00 2016 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Aug 29 20:51:16 2016 +0200
debug: better verbose message
---
lib/metadata/pool_manip.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/lib/metadata/pool_manip.c b/lib/metadata/pool_manip.c
index f292a0c..a0fe11c 100644
--- a/lib/metadata/pool_manip.c
+++ b/lib/metadata/pool_manip.c
@@ -525,7 +525,7 @@ int update_pool_params(const struct segment_type *segtype,
return 0;
}
- log_verbose("Using pool metadata size %s.",
+ log_verbose("Preferred pool metadata size %s.",
display_size(vg->cmd, (uint64_t)*pool_metadata_extents * vg->extent_size));
return 1;
7 years, 3 months
master - cleanup: clean gcc6 minor/major types warnings
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=92d5a8441007f5...
Commit: 92d5a8441007f578e000b492cecf67d6b8a87405
Parent: 81970d22d8a841c1ea69fde5c9108fc4df3759bd
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Thu Aug 18 14:41:46 2016 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Aug 29 20:51:16 2016 +0200
cleanup: clean gcc6 minor/major types warnings
Put sys/sysmacros.h in front of sys/types.h header file as requested
by gcc6.
---
lib/filters/filter-sysfs.c | 1 +
libdm/libdm-stats.c | 1 +
2 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/lib/filters/filter-sysfs.c b/lib/filters/filter-sysfs.c
index 3115f86..6f566bc 100644
--- a/lib/filters/filter-sysfs.c
+++ b/lib/filters/filter-sysfs.c
@@ -17,6 +17,7 @@
#ifdef __linux__
+#include <sys/sysmacros.h>
#include <dirent.h>
static int _locate_sysfs_blocks(const char *sysfs_dir, char *path, size_t len,
diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c
index 1c2e19b..6932b28 100644
--- a/libdm/libdm-stats.c
+++ b/libdm/libdm-stats.c
@@ -19,6 +19,7 @@
#include "math.h" /* log10() */
+#include <sys/sysmacros.h>
#include <sys/ioctl.h>
#include <sys/vfs.h> /* fstatfs */
7 years, 3 months
master - cache: do not monitor cache-pool
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=81970d22d8a841...
Commit: 81970d22d8a841c1ea69fde5c9108fc4df3759bd
Parent: b493811968b34876ef558ad04d18c1b76bd28113
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Wed Aug 24 10:05:09 2016 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Aug 29 20:51:15 2016 +0200
cache: do not monitor cache-pool
Avoid monitoring of activated cache-pool - where the only purpose ATM
is to clear metadata volume which is actually activate in place
of cache-pool name (using public LV name).
Since VG lock is held across whole clear operation, dmeventd cannot
be used anyway - however in case of appliction crash we may
leave unmonitored device.
In future we may provide better mechanism as the current name
replacemnet is creating 'uncommon' table setups in case the metadata
LV is more complex type like raid (needs some futher thinking about
error path results).
Another point to think about is the fact we should not clear device
while holding lock (i.e. dmeventd mirror repair cannot work in cases
like this).
---
WHATS_NEW | 1 +
lib/activate/activate.c | 17 +++++++++++++++++
2 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index 76e203d..6980e17 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.165 -
===================================
+ Do not monitor cache-pool metadata when LV is just being cleared.
Add allocation/cache_pool_max_chunks to prevent misuse of cache target.
Give error not segfault in lvconvert --splitmirrors when PV lies outside LV.
Fix typo in report/columns_as_rows config option name recognition (2.02.99).
diff --git a/lib/activate/activate.c b/lib/activate/activate.c
index f4d3a17..9977291 100644
--- a/lib/activate/activate.c
+++ b/lib/activate/activate.c
@@ -1724,6 +1724,23 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
return 1;
/*
+ * Activation of unused cache-pool activates metadata device as
+ * a public LV for clearing purpose.
+ * FIXME:
+ * As VG lock is held across whole operation unmonitored volume
+ * is usually OK since dmeventd couldn't do anything.
+ * However in case command would have crashed, such LV is
+ * left unmonitored and may potentially require dmeventd.
+ */
+ if ((lv_is_cache_pool_data(lv) || lv_is_cache_pool_metadata(lv)) &&
+ !lv_is_used_cache_pool((find_pool_seg(first_seg(lv))->lv))) {
+ log_debug_activation("Skipping %smonitor of %s.%s",
+ (monitor) ? "" : "un", display_lvname(lv),
+ (monitor) ? " Cache pool activation for clearing only." : "");
+ return 1;
+ }
+
+ /*
* Allow to unmonitor thin pool via explicit pool unmonitor
* or unmonitor before the last thin pool user deactivation
* Skip unmonitor, if invoked via deactivation of thin volume
7 years, 3 months
master - cache: introduce cache_pool_max_chunks
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=b493811968b348...
Commit: b493811968b34876ef558ad04d18c1b76bd28113
Parent: 2fde4399a01a002437d6d882c7faa59221aca93e
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Wed Aug 24 10:16:01 2016 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Aug 29 20:47:31 2016 +0200
cache: introduce cache_pool_max_chunks
Introduce 'hard limit' for max number of cache chunks.
When cache target operates with too many chunks (>10e6).
When user is aware of related possible troubles he
may increase the limit in lvm.conf.
Also verbosely inform user about possible solution.
Code works for both lvcreate and lvconvert.
Lvconvert fully supports change of chunk_size when caching LV
(and validates for compatible settings).
---
WHATS_NEW | 1 +
lib/config/config.c | 22 +++++++++++
lib/config/config.h | 1 +
lib/config/config_settings.h | 5 ++
lib/config/defaults.h | 1 +
lib/metadata/cache_manip.c | 68 ++++++++++++++++++++++++++++++----
test/shell/lvconvert-cache-chunks.sh | 53 ++++++++++++++++++++++++++
tools/lvconvert.c | 10 ++++-
8 files changed, 151 insertions(+), 10 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index 1c0bcf4..76e203d 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.165 -
===================================
+ Add allocation/cache_pool_max_chunks to prevent misuse of cache target.
Give error not segfault in lvconvert --splitmirrors when PV lies outside LV.
Fix typo in report/columns_as_rows config option name recognition (2.02.99).
Avoid PV tags when checking allocation against parallel PVs.
diff --git a/lib/config/config.c b/lib/config/config.c
index 46ef8e7..820a744 100644
--- a/lib/config/config.c
+++ b/lib/config/config.c
@@ -2461,3 +2461,25 @@ int get_default_allocation_cache_pool_chunk_size_CFG(struct cmd_context *cmd, st
{
return DEFAULT_CACHE_POOL_CHUNK_SIZE * 2;
}
+
+uint64_t get_default_allocation_cache_pool_max_chunks_CFG(struct cmd_context *cmd, struct profile *profile)
+{
+ static int _warn_max_chunks = 0;
+ /*
+ * TODO: In future may depend on the cache target version,
+ * newer targets may scale better.
+ */
+ uint64_t default_max_chunks = DEFAULT_CACHE_POOL_MAX_CHUNKS;
+ uint64_t max_chunks = find_config_tree_int(cmd, allocation_cache_pool_max_chunks_CFG, profile);
+
+ if (!max_chunks)
+ max_chunks = default_max_chunks;
+ else if (max_chunks > default_max_chunks)
+ /* Still warn the user when the value is tweaked above recommended level */
+ /* Maybe drop to log_verbose... */
+ log_warn_suppress(_warn_max_chunks++, "WARNING: Configured cache_pool_max_chunks value "
+ FMTu64 " is higher then recommended " FMTu64 ".",
+ max_chunks, default_max_chunks);
+
+ return max_chunks;
+}
diff --git a/lib/config/config.h b/lib/config/config.h
index aa95202..f0202b6 100644
--- a/lib/config/config.h
+++ b/lib/config/config.h
@@ -307,5 +307,6 @@ int get_default_allocation_cache_pool_chunk_size_CFG(struct cmd_context *cmd, st
#define get_default_unconfigured_allocation_cache_pool_chunk_size_CFG NULL
const char *get_default_allocation_cache_policy_CFG(struct cmd_context *cmd, struct profile *profile);
#define get_default_unconfigured_allocation_cache_policy_CFG NULL
+uint64_t get_default_allocation_cache_pool_max_chunks_CFG(struct cmd_context *cmd, struct profile *profile);
#endif
diff --git a/lib/config/config_settings.h b/lib/config/config_settings.h
index 7401725..9eed969 100644
--- a/lib/config/config_settings.h
+++ b/lib/config/config_settings.h
@@ -516,6 +516,11 @@ cfg_runtime(allocation_cache_pool_chunk_size_CFG, "cache_pool_chunk_size", alloc
"on the smaller end of the spectrum. Supported values range from\n"
"32KiB to 1GiB in multiples of 32.\n")
+cfg(allocation_cache_pool_max_chunks_CFG, "cache_pool_max_chunks", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_UNDEFINED, CFG_TYPE_INT, 0, vsn(2, 2, 165), NULL, 0, NULL,
+ "The maximum number of chunks in a cache pool.\n"
+ "For cache target v1.9 the recommended maximumm is 1000000 chunks.\n"
+ "Using cache pool with more chunks may degrade cache performance.\n")
+
cfg(allocation_thin_pool_metadata_require_separate_pvs_CFG, "thin_pool_metadata_require_separate_pvs", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS, vsn(2, 2, 89), NULL, 0, NULL,
"Thin pool metdata and data will always use different PVs.\n")
diff --git a/lib/config/defaults.h b/lib/config/defaults.h
index c6efcdc..d988779 100644
--- a/lib/config/defaults.h
+++ b/lib/config/defaults.h
@@ -127,6 +127,7 @@
#define DEFAULT_CACHE_REPAIR_OPTIONS_CONFIG "#S" DEFAULT_CACHE_REPAIR_OPTION1
#define DEFAULT_CACHE_POOL_METADATA_REQUIRE_SEPARATE_PVS 0
#define DEFAULT_CACHE_POOL_CHUNK_SIZE 64 /* KB */
+#define DEFAULT_CACHE_POOL_MAX_CHUNKS 1000000
#define DEFAULT_CACHE_POOL_MIN_METADATA_SIZE 2048 /* KB */
#define DEFAULT_CACHE_POOL_MAX_METADATA_SIZE (16 * 1024 * 1024) /* KB */
#define DEFAULT_CACHE_POLICY "mq"
diff --git a/lib/metadata/cache_manip.c b/lib/metadata/cache_manip.c
index 275696e..d73142d 100644
--- a/lib/metadata/cache_manip.c
+++ b/lib/metadata/cache_manip.c
@@ -161,9 +161,40 @@ int update_cache_pool_params(const struct segment_type *segtype,
uint64_t min_meta_size;
uint32_t extent_size = vg->extent_size;
uint64_t pool_metadata_size = (uint64_t) *pool_metadata_extents * extent_size;
-
- if (!(passed_args & PASS_ARG_CHUNK_SIZE))
+ uint64_t pool_data_size = (uint64_t) pool_data_extents * extent_size;
+ uint64_t max_chunks =
+ get_default_allocation_cache_pool_max_chunks_CFG(vg->cmd, vg->profile);
+ /* min chunk size in a multiple of DM_CACHE_MIN_DATA_BLOCK_SIZE */
+ uint64_t min_chunk_size = (((pool_data_size + max_chunks - 1) / max_chunks +
+ DM_CACHE_MIN_DATA_BLOCK_SIZE - 1) /
+ DM_CACHE_MIN_DATA_BLOCK_SIZE) * DM_CACHE_MIN_DATA_BLOCK_SIZE;
+
+ if (!(passed_args & PASS_ARG_CHUNK_SIZE)) {
*chunk_size = DEFAULT_CACHE_POOL_CHUNK_SIZE * 2;
+ if (*chunk_size < min_chunk_size) {
+ /*
+ * When using more then 'standard' default,
+ * keep user informed he might be using things in untintended direction
+ */
+ log_print_unless_silent("Using %s chunk size instead of default %s, "
+ "so cache pool has less then " FMTu64 " chunks.",
+ display_size(vg->cmd, min_chunk_size),
+ display_size(vg->cmd, *chunk_size),
+ max_chunks);
+ *chunk_size = min_chunk_size;
+ } else
+ log_verbose("Setting chunk size to %s.",
+ display_size(vg->cmd, *chunk_size));
+ } else if (*chunk_size < min_chunk_size) {
+ log_error("Chunk size %s is less then required minimal chunk size %s "
+ "for a cache pool of %s size and limit " FMTu64 " chunks.",
+ display_size(vg->cmd, *chunk_size),
+ display_size(vg->cmd, min_chunk_size),
+ display_size(vg->cmd, pool_data_size),
+ max_chunks);
+ log_error("To allow use of more chunks, see setting allocation/cache_pool_max_chunks.");
+ return 0;
+ }
if (!validate_pool_chunk_size(vg->cmd, segtype, *chunk_size))
return_0;
@@ -204,18 +235,39 @@ int update_cache_pool_params(const struct segment_type *segtype,
*/
int validate_lv_cache_chunk_size(struct logical_volume *pool_lv, uint32_t chunk_size)
{
+ struct volume_group *vg = pool_lv->vg;
+ uint64_t max_chunks = get_default_allocation_cache_pool_max_chunks_CFG(vg->cmd, vg->profile);
uint64_t min_size = _cache_min_metadata_size(pool_lv->size, chunk_size);
+ uint64_t chunks = pool_lv->size / chunk_size;
+ int r = 1;
if (min_size > first_seg(pool_lv)->metadata_lv->size) {
- log_error("Cannot use chunk size %s with cache pool %s. "
- "Minimal required size for metadata is %s.",
- display_size(pool_lv->vg->cmd, chunk_size),
+ log_error("Cannot use chunk size %s with cache pool %s metadata size %s.",
+ display_size(vg->cmd, chunk_size),
display_lvname(pool_lv),
- display_size(pool_lv->vg->cmd, min_size));
- return 0;
+ display_size(vg->cmd, first_seg(pool_lv)->metadata_lv->size));
+ log_error("Minimal size for cache pool %s metadata with chunk size %s would be %s.",
+ display_lvname(pool_lv),
+ display_size(vg->cmd, chunk_size),
+ display_size(vg->cmd, min_size));
+ r = 0;
}
- return 1;
+ if (chunks > max_chunks) {
+ log_error("Cannot use too small chunk size %s with cache pool %s data volume size %s.",
+ display_size(vg->cmd, chunk_size),
+ display_lvname(pool_lv),
+ display_size(pool_lv->vg->cmd, pool_lv->size));
+ log_error("Maximum configured chunks for a cache pool is " FMTu64 ".",
+ max_chunks);
+ log_error("Use smaller cache pool (<%s) or bigger cache chunk size (>=%s) or enable higher "
+ "values in 'allocation/cache_pool_max_chunks'.",
+ display_size(vg->cmd, chunk_size * max_chunks),
+ display_size(vg->cmd, pool_lv->size / max_chunks));
+ r = 0;
+ }
+
+ return r;
}
/*
* Validate arguments for converting origin into cached volume with given cache pool.
diff --git a/test/shell/lvconvert-cache-chunks.sh b/test/shell/lvconvert-cache-chunks.sh
new file mode 100644
index 0000000..806db0f
--- /dev/null
+++ b/test/shell/lvconvert-cache-chunks.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+# Copyright (C) 2016 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise number of cache chunks in cache pool
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_cache 1 3 0 || skip
+
+aux prepare_vg 2 1000000
+
+# Really large cache pool data LV
+lvcreate -L1T -n cpool $vg
+
+# Works and pick higher chunks size then default
+lvconvert -y --type cache-pool $vg/cpool
+
+# Check chunk size in sectors is more then 512K
+test $(get lv_field $vg/cpool chunk_size --units s --nosuffix) -gt 1000
+
+lvcreate -L1M -n $lv1 $vg
+
+# Not let pass small chunks when caching origin
+fail lvconvert -H --chunksize 128K --cachepool $vg/cpool $vg/$lv1
+
+# Though 2M is valid
+lvconvert -y -H --chunksize 2M --cachepool $vg/cpool $vg/$lv1
+
+lvremove -f $vg
+
+###
+
+# Really large cache pool data LV
+lvcreate -L1T -n cpool $vg
+# Not allowed to create more then 10e6 chunks
+fail lvconvert -y --type cache-pool --chunksize 128K $vg/cpool
+
+# Let operation pass when max_chunk limit is raised
+lvconvert -y --type cache-pool --chunksize 128K $vg/cpool \
+ --config 'allocation/cache_pool_max_chunks=10000000'
+
+vgremove -f $vg
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 457724c..d1d21b6 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -3037,16 +3037,22 @@ static int _lvconvert_pool(struct cmd_context *cmd,
if (!metadata_lv) {
if (arg_from_list_is_set(cmd, "is invalid with existing pool",
- chunksize_ARG, discards_ARG,
+ discards_ARG,
poolmetadatasize_ARG, -1))
return_0;
if (lp->thin &&
arg_from_list_is_set(cmd, "is invalid with existing thin pool",
- zero_ARG, -1))
+ chunksize_ARG, zero_ARG, -1))
return_0;
if (lp->cache) {
+ if (!lp->chunk_size)
+ lp->chunk_size = first_seg(pool_lv)->chunk_size;
+
+ if (!validate_lv_cache_chunk_size(pool_lv, lp->chunk_size))
+ return_0;
+
/* Check is user requested zeroing logic via [-Z y|n] */
if (!arg_is_set(cmd, zero_ARG)) {
/* Note: requires rather deep know-how to skip zeroing */
7 years, 3 months
master - lvconvert: Fix --splitmirrors segfault with incorrect PV.
by Alasdair Kergon
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=2fde4399a01a00...
Commit: 2fde4399a01a002437d6d882c7faa59221aca93e
Parent: fc93f10892187e20f9553b2d0c953cc420fd379d
Author: Alasdair G Kergon <agk(a)redhat.com>
AuthorDate: Fri Aug 26 01:21:01 2016 +0100
Committer: Alasdair G Kergon <agk(a)redhat.com>
CommitterDate: Fri Aug 26 01:21:01 2016 +0100
lvconvert: Fix --splitmirrors segfault with incorrect PV.
Commit 9ee071705b2c35e1132f39f5731861c831a1bb6b misunderstood integer
promotion, but it's simpler to detect -1 more directly.
---
WHATS_NEW | 1 +
lib/metadata/raid_manip.c | 2 +-
2 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index 99d31be..1c0bcf4 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.165 -
===================================
+ Give error not segfault in lvconvert --splitmirrors when PV lies outside LV.
Fix typo in report/columns_as_rows config option name recognition (2.02.99).
Avoid PV tags when checking allocation against parallel PVs.
Disallow mirror conversions of raid10 volumes.
diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c
index d0934f4..e5fdf4f 100644
--- a/lib/metadata/raid_manip.c
+++ b/lib/metadata/raid_manip.c
@@ -1497,7 +1497,7 @@ int lv_raid_split_and_track(struct logical_volume *lv,
break;
}
- if (s >= (int) seg->area_count) {
+ if (s < 0) {
log_error("Unable to find image to satisfy request");
return 0;
}
7 years, 3 months
master - tests: also fix typo in report/columns_as_rows in tests
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=fc93f10892187e...
Commit: fc93f10892187e20f9553b2d0c953cc420fd379d
Parent: e758d722c7719fba91ae62122fb0359a395f0327
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Thu Aug 25 16:25:23 2016 +0200
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Thu Aug 25 16:25:23 2016 +0200
tests: also fix typo in report/columns_as_rows in tests
---
test/shell/profiles.sh | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/test/shell/profiles.sh b/test/shell/profiles.sh
index 037b306..562b7b1 100644
--- a/test/shell/profiles.sh
+++ b/test/shell/profiles.sh
@@ -59,7 +59,7 @@ aux profileconf valid_cmd_profile 'global/units = "h"' \
'report/separator = " "' \
'report/prefixes = 0' \
'report/quoted = 1' \
- 'report/colums_as_rows = 0' \
+ 'report/columns_as_rows = 0' \
'report/devtypes_sort = "devtype_name"' \
'report/devtypes_cols = "devtype_name,devtype_max_partitions,devtype_description"' \
'report/devtypes_cols_verbose = "devtype_name,devtype_max_partitions,devtype_description"' \
7 years, 3 months