Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=53ef4967192ce8bf…
Commit: 53ef4967192ce8bfe5eaebf8104a1f7cbf8ab020
Parent: 1d520909534e1a4e1adf2513a5061adfe631d6af
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Wed Nov 30 13:39:48 2016 -0600
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Wed Nov 30 15:59:06 2016 -0600
lvmdbusd: Emit signal on Job completion
Added a properties changed signal on the job dbus object so that client
can wait for a signal that the job is complete instead of polling or
blocking on the wait method.
---
daemons/lvmdbusd/job.py | 8 +++++++-
daemons/lvmdbusd/request.py | 1 -
daemons/lvmdbusd/utils.py | 5 +++++
3 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/daemons/lvmdbusd/job.py b/daemons/lvmdbusd/job.py
index ec6d6b6..609b747 100644
--- a/daemons/lvmdbusd/job.py
+++ b/daemons/lvmdbusd/job.py
@@ -8,7 +8,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from .automatedproperties import AutomatedProperties
-from .utils import job_obj_path_generate, mt_async_result
+from .utils import job_obj_path_generate, mt_async_result, mt_run_no_wait
from . import cfg
from .cfg import JOB_INTERFACE
import dbus
@@ -180,9 +180,15 @@ class Job(AutomatedProperties):
def Complete(self):
return dbus.Boolean(self.state.Complete)
+ @staticmethod
+ def _signal_complete(obj):
+ obj.PropertiesChanged(
+ JOB_INTERFACE, dict(Complete=dbus.Boolean(obj.state.Complete)), [])
+
@Complete.setter
def Complete(self, value):
self.state.Complete = value
+ mt_run_no_wait(Job._signal_complete, self)
@property
def GetError(self):
diff --git a/daemons/lvmdbusd/request.py b/daemons/lvmdbusd/request.py
index ca45e8c..a2c2ac9 100644
--- a/daemons/lvmdbusd/request.py
+++ b/daemons/lvmdbusd/request.py
@@ -126,7 +126,6 @@ class RequestEntry(object):
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.
self._job.Complete = True
self._job = None
diff --git a/daemons/lvmdbusd/utils.py b/daemons/lvmdbusd/utils.py
index abee659..b95f80a 100644
--- a/daemons/lvmdbusd/utils.py
+++ b/daemons/lvmdbusd/utils.py
@@ -515,6 +515,11 @@ def mt_async_result(call_back, results):
GLib.idle_add(_async_result, call_back, results)
+# Take the supplied function and run it on the main thread and not wait for
+# a result!
+def mt_run_no_wait(function, param):
+ GLib.idle_add(function, param)
+
# 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.
#
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=1d520909534e1a4e…
Commit: 1d520909534e1a4e1adf2513a5061adfe631d6af
Parent: 37f05ccab1a576bdd71be1f4f80ab6f621042d71
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Wed Nov 30 13:03:25 2016 -0600
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Wed Nov 30 15:59:06 2016 -0600
lvmdbusd: Remove TODO on concurrent access to properties
As the code now uses a single thread to handle all changes to the
dbus model we no longer need to handle this potential race
condition.
---
daemons/lvmdbusd/automatedproperties.py | 5 +----
1 files changed, 1 insertions(+), 4 deletions(-)
diff --git a/daemons/lvmdbusd/automatedproperties.py b/daemons/lvmdbusd/automatedproperties.py
index 5e14d61..7b22d19 100644
--- a/daemons/lvmdbusd/automatedproperties.py
+++ b/daemons/lvmdbusd/automatedproperties.py
@@ -159,10 +159,7 @@ class AutomatedProperties(dbus.service.Object):
cfg.om.lookup_update(self, new_id[0], new_id[1])
# Grab the properties values, then replace the state of the object
- # and retrieve the new values
- # TODO: We need to add locking to prevent concurrent access to the
- # properties so that a client is not accessing while we are
- # replacing.
+ # and retrieve the new values.
o_prop = get_properties(self)
self.state = new_state
n_prop = get_properties(self)
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=37f05ccab1a576bd…
Commit: 37f05ccab1a576bdd71be1f4f80ab6f621042d71
Parent: 3bc69cb23c29e8e016282508514ce191c756b89c
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Wed Nov 30 12:59:46 2016 -0600
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Wed Nov 30 15:59:06 2016 -0600
lvmdbusd: Supress protected member access warning
We want _run to be protected so that users outside of the class
don't mistakenly use it. It's for internal use only.
---
daemons/lvmdbusd/utils.py | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/daemons/lvmdbusd/utils.py b/daemons/lvmdbusd/utils.py
index 561b158..abee659 100644
--- a/daemons/lvmdbusd/utils.py
+++ b/daemons/lvmdbusd/utils.py
@@ -525,6 +525,7 @@ class MThreadRunner(object):
@staticmethod
def runner(obj):
+ # noinspection PyProtectedMember
obj._run()
with obj.cond:
obj.function_complete = True
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=3bc69cb23c29e8e0…
Commit: 3bc69cb23c29e8e016282508514ce191c756b89c
Parent: b0757ac96e5c0f50e8d088200eb1ad62e535fcb6
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Tue Nov 29 18:01:56 2016 -0600
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Wed Nov 30 15:59:06 2016 -0600
lvmdbusd: Add --blackboxsize command line argument
Allows the user to override the number of commands that get dumped
to the log when we encounter a lvm error. Also useful during
development when you don't want to see the blackbox output.
---
daemons/lvmdbusd/cmdhandler.py | 13 +++++++------
daemons/lvmdbusd/main.py | 16 ++++++++++++++--
2 files changed, 21 insertions(+), 8 deletions(-)
diff --git a/daemons/lvmdbusd/cmdhandler.py b/daemons/lvmdbusd/cmdhandler.py
index f221f93..f1591aa 100644
--- a/daemons/lvmdbusd/cmdhandler.py
+++ b/daemons/lvmdbusd/cmdhandler.py
@@ -55,18 +55,19 @@ class LvmExecutionMeta(object):
class LvmFlightRecorder(object):
- def __init__(self):
- self.queue = collections.deque(maxlen=16)
+ def __init__(self, size=16):
+ self.queue = collections.deque(maxlen=size)
def add(self, lvm_exec_meta):
self.queue.append(lvm_exec_meta)
def dump(self):
with cmd_lock:
- log_error("LVM dbus flight recorder START")
- for c in self.queue:
- log_error(str(c))
- log_error("LVM dbus flight recorder END")
+ if len(self.queue):
+ log_error("LVM dbus flight recorder START")
+ for c in self.queue:
+ log_error(str(c))
+ log_error("LVM dbus flight recorder END")
cfg.blackbox = LvmFlightRecorder()
diff --git a/daemons/lvmdbusd/main.py b/daemons/lvmdbusd/main.py
index 4b9f94e..9bf0871 100644
--- a/daemons/lvmdbusd/main.py
+++ b/daemons/lvmdbusd/main.py
@@ -29,6 +29,7 @@ from .utils import log_debug, log_error
import argparse
import os
import sys
+from .cmdhandler import LvmFlightRecorder
class Lvm(objectmanager.ObjectManager):
@@ -75,6 +76,12 @@ def main():
help="Use the lvm shell, not fork & exec lvm",
default=False,
dest='use_lvm_shell')
+ parser.add_argument(
+ "--blackboxsize",
+ help="Size of the black box flight recorder, 0 to disable",
+ default=10,
+ type=int,
+ dest='bb_size')
use_session = os.getenv('LVMDBUSD_USE_SESSION', False)
@@ -83,6 +90,11 @@ def main():
cfg.args = parser.parse_args()
+ # We create a flight recorder in cmdhandler too, but we replace it here
+ # as the user may be specifying a different size. The default one in
+ # cmdhandler is for when we are running other code with a different main.
+ cfg.blackbox = LvmFlightRecorder(cfg.args.bb_size)
+
if cfg.args.use_lvm_shell and not cfg.args.use_json:
log_error("You cannot specify --lvmshell and --nojson")
sys.exit(1)
@@ -118,8 +130,8 @@ def main():
# thread that is handling the dbus interface
thread_list.append(threading.Thread(target=process_request))
- # Have a single thread handling updating lvm and the dbus model so we don't
- # have multiple threads doing this as the same time
+ # Have a single thread handling updating lvm and the dbus model so we
+ # don't have multiple threads doing this as the same time
updater = StateUpdate()
thread_list.append(updater.thread)
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=0b8bf73a63d8dbd9…
Commit: 0b8bf73a63d8dbd9fa32a32c7d47a277d4fb8eb1
Parent: 58f4d98af11eaf21df00aaaf987ca6a92039db7f
Author: Heinz Mauelshagen <heinzm(a)redhat.com>
AuthorDate: Wed Nov 30 22:56:37 2016 +0100
Committer: Heinz Mauelshagen <heinzm(a)redhat.com>
CommitterDate: Wed Nov 30 22:57:54 2016 +0100
lvchange: allow a transiently failed RaidLV to be refreshed
In case any SubLV of a RaidLV transiently fails, it needs
two "lvchange --refresh RaidLV" runs to get it to fully
operational mode again. Reason being, that lvm reloads all
targets for the RaidLV tree but doesn't resume the SubLVs
until after the whole tree has been reloaded in the first
refresh run. Thus the live mapping table of the SubLVs
still point to an "error" mapping and the dm-raid target
can't retrieve any superblock from the MetaLV(s) in processing
the constructor during this preload thus not discovering the
again accessible SubLVs. In the second run, the SubLV targets
map proper (meta)data, hence the constructor discovers those
fine now.
Solve by resuming the SubLVs of the RaidLV before
preloading the respective top-level RaidLV target.
Resolves: rhbz1399844
---
lib/metadata/lv_manip.c | 29 ++++++++++++++++++++++++++++-
1 files changed, 28 insertions(+), 1 deletions(-)
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 10c0446..120217f 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -1382,7 +1382,7 @@ int replace_lv_with_error_segment(struct logical_volume *lv)
return 1;
}
-int lv_refresh_suspend_resume(const struct logical_volume *lv)
+static int _lv_refresh_suspend_resume(const struct logical_volume *lv)
{
struct cmd_context *cmd = lv->vg->cmd;
int r = 1;
@@ -1407,6 +1407,33 @@ int lv_refresh_suspend_resume(const struct logical_volume *lv)
return r;
}
+int lv_refresh_suspend_resume(const struct logical_volume *lv)
+{
+ /*
+ * FIXME:
+ *
+ * in case of RAID, refresh the SubLVs before
+ * refreshing the top-level one in order to cope
+ * with transient failures of SubLVs.
+ */
+ if (lv_is_raid(lv)) {
+ uint32_t s;
+ struct lv_segment *seg = first_seg(lv);
+
+ for (s = 0; s < seg->area_count; s++) {
+ if (seg_type(seg, s) == AREA_LV &&
+ !_lv_refresh_suspend_resume(seg_lv(seg, s)))
+ return 0;
+ if (seg->meta_areas &&
+ seg_metatype(seg, s) == AREA_LV &&
+ !_lv_refresh_suspend_resume(seg_metalv(seg, s)))
+ return 0;
+ }
+ }
+
+ return _lv_refresh_suspend_resume(lv);
+}
+
/*
* Remove given number of extents from LV.
*/
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=d882edb32d8695ff…
Commit: d882edb32d8695ffb1498759649af93f407f39db
Parent: 25b5413f895bc61357ef4afab255e3125335d4ec
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Tue Nov 29 12:37:59 2016 -0600
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Tue Nov 29 16:50:30 2016 -0600
lvmdbusd: Simplfy reading streams
Remove redundant code and make code paths the same for all streams.
---
daemons/lvmdbusd/lvm_shell_proxy.py | 52 +++++++++++++++++------------------
1 files changed, 25 insertions(+), 27 deletions(-)
diff --git a/daemons/lvmdbusd/lvm_shell_proxy.py b/daemons/lvmdbusd/lvm_shell_proxy.py
index 464da79..ae8049f 100755
--- a/daemons/lvmdbusd/lvm_shell_proxy.py
+++ b/daemons/lvmdbusd/lvm_shell_proxy.py
@@ -43,6 +43,13 @@ def _quote_arg(arg):
class LVMShellProxy(object):
+ @staticmethod
+ def _read(stream):
+ tmp = stream.read()
+ if tmp:
+ return tmp.decode("utf-8")
+ return ''
+
# Read until we get prompt back and a result
# @param: no_output Caller expects no output to report FD
# Returns stdout, report, stderr (report is JSON!)
@@ -62,29 +69,17 @@ class LVMShellProxy(object):
try:
rd_fd = [
self.lvm_shell.stdout.fileno(),
- self.report_r,
+ self.report_stream.fileno(),
self.lvm_shell.stderr.fileno()]
ready = select.select(rd_fd, [], [], 2)
for r in ready[0]:
if r == self.lvm_shell.stdout.fileno():
- tmp = self.lvm_shell.stdout.read()
- if tmp:
- stdout += tmp.decode("utf-8")
- 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
- else:
- break
-
+ stdout += LVMShellProxy._read(self.lvm_shell.stdout)
+ elif r == self.report_stream.fileno():
+ report += LVMShellProxy._read(self.report_stream)
elif r == self.lvm_shell.stderr.fileno():
- tmp = self.lvm_shell.stderr.read()
- if tmp:
- stderr += tmp.decode("utf-8")
+ stderr += LVMShellProxy._read(self.lvm_shell.stderr)
# Check to see if the lvm process died on us
if self.lvm_shell.poll():
@@ -131,6 +126,11 @@ class LVMShellProxy(object):
assert (num_written == len(cmd_bytes))
self.lvm_shell.stdin.flush()
+ @staticmethod
+ def _make_non_block(stream):
+ flags = fcntl(stream, F_GETFL)
+ fcntl(stream, F_SETFL, flags | os.O_NONBLOCK)
+
def __init__(self):
# Create a temp directory
@@ -143,7 +143,10 @@ class LVMShellProxy(object):
except FileExistsError:
pass
- self.report_r = os.open(tmp_file, os.O_NONBLOCK)
+ # We have to open non-blocking as the other side isn't open until
+ # we actually fork the process.
+ self.report_fd = os.open(tmp_file, os.O_NONBLOCK)
+ self.report_stream = os.fdopen(self.report_fd, 'rb', 0)
# Setup the environment for using our own socket for reporting
local_env = copy.deepcopy(os.environ)
@@ -154,9 +157,6 @@ class LVMShellProxy(object):
# when utilizing the lvm shell.
local_env["LVM_LOG_FILE_MAX_LINES"] = "0"
- 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 + " 32>%s" % tmp_file],
@@ -164,10 +164,8 @@ class LVMShellProxy(object):
stderr=subprocess.PIPE, close_fds=True, shell=True)
try:
- flags = fcntl(self.lvm_shell.stdout, F_GETFL)
- 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 | os.O_NONBLOCK)
+ LVMShellProxy._make_non_block(self.lvm_shell.stdout)
+ LVMShellProxy._make_non_block(self.lvm_shell.stderr)
# wait for the first prompt
errors = self._read_until_prompt(no_output=True)[2]
@@ -176,8 +174,8 @@ class LVMShellProxy(object):
except:
raise
finally:
- # 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
+ # 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)