From: Tony Asleson <tasleson@sourceware.org>
To: lvm-devel@redhat.com
Subject: main - lvmdbusd: Add lockfile
Date: Mon, 19 Sep 2022 15:57:49 +0000 (GMT) [thread overview]
Message-ID: <20220919155749.E9B533858C53@sourceware.org> (raw)
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=3fdf4493481ff8baae2ac5416dce6d05b69e6b28
Commit: 3fdf4493481ff8baae2ac5416dce6d05b69e6b28
Parent: 1a4384979cdf889bd63a932d83933079c53490ae
Author: Tony Asleson <tasleson@redhat.com>
AuthorDate: Mon Aug 8 20:48:10 2022 -0500
Committer: Tony Asleson <tasleson@redhat.com>
CommitterDate: Fri Sep 16 10:49:36 2022 -0500
lvmdbusd: Add lockfile
The daemon cannot handle multiple copies of itself running at the
same time, ensure this cannot happen.
---
daemons/lvmdbusd/cfg.py | 2 +
daemons/lvmdbusd/main.py | 111 +++++++++++++++++++++++-----------------------
daemons/lvmdbusd/utils.py | 37 ++++++++++++++--
3 files changed, 92 insertions(+), 58 deletions(-)
diff --git a/daemons/lvmdbusd/cfg.py b/daemons/lvmdbusd/cfg.py
index 684c2b208..ee4e41b30 100644
--- a/daemons/lvmdbusd/cfg.py
+++ b/daemons/lvmdbusd/cfg.py
@@ -16,6 +16,8 @@ from lvmdbusd import path
LVM_CMD = os.getenv('LVM_BINARY', path.LVM_BINARY)
+LOCK_FILE = os.getenv("LVM_DBUSD_LOCKFILE", "/var/lock/lvm/lvmdbusd")
+
# This is the global object manager
om = None
diff --git a/daemons/lvmdbusd/main.py b/daemons/lvmdbusd/main.py
index 1e883c901..7b455052e 100644
--- a/daemons/lvmdbusd/main.py
+++ b/daemons/lvmdbusd/main.py
@@ -154,61 +154,62 @@ def main():
install_signal_handlers()
- dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
- dbus.mainloop.glib.threads_init()
+ with utils.LockFile(cfg.LOCK_FILE):
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+ dbus.mainloop.glib.threads_init()
- cmdhandler.set_execution(cfg.args.use_lvm_shell)
+ cmdhandler.set_execution(cfg.args.use_lvm_shell)
- if use_session:
- cfg.bus = dbus.SessionBus()
- else:
- cfg.bus = dbus.SystemBus()
- # The base name variable needs to exist for things to work.
- # noinspection PyUnusedLocal
- base_name = dbus.service.BusName(BUS_NAME, cfg.bus)
- cfg.om = Lvm(BASE_OBJ_PATH)
- cfg.om.register_object(Manager(MANAGER_OBJ_PATH))
-
- cfg.db = lvmdb.DataStore(vdo_support=cfg.vdo_support)
-
- # 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, name='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
- updater = StateUpdate()
- thread_list.append(updater.thread)
-
- cfg.load = updater.load
-
- cfg.loop = GLib.MainLoop()
-
- for thread in thread_list:
- thread.damon = True
- thread.start()
-
- # 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')
-
- try:
- if cfg.run.value != 0:
- cfg.loop.run()
- udevwatch.remove()
-
- for thread in thread_list:
- thread.join()
- except KeyboardInterrupt:
- # If we are unable to register signal handler, we will end up here when
- # the service gets a ^C or a kill -2 <parent pid>
- utils.handler(signal.SIGINT)
+ if use_session:
+ cfg.bus = dbus.SessionBus()
+ else:
+ cfg.bus = dbus.SystemBus()
+ # The base name variable needs to exist for things to work.
+ # noinspection PyUnusedLocal
+ base_name = dbus.service.BusName(BUS_NAME, cfg.bus)
+ cfg.om = Lvm(BASE_OBJ_PATH)
+ cfg.om.register_object(Manager(MANAGER_OBJ_PATH))
+
+ cfg.db = lvmdb.DataStore(vdo_support=cfg.vdo_support)
+
+ # 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, name='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
+ updater = StateUpdate()
+ thread_list.append(updater.thread)
+
+ cfg.load = updater.load
+
+ cfg.loop = GLib.MainLoop()
+
+ for thread in thread_list:
+ thread.damon = True
+ thread.start()
+
+ # 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')
+
+ try:
+ if cfg.run.value != 0:
+ cfg.loop.run()
+ udevwatch.remove()
+
+ for thread in thread_list:
+ thread.join()
+ except KeyboardInterrupt:
+ # If we are unable to register signal handler, we will end up here when
+ # the service gets a ^C or a kill -2 <parent pid>
+ utils.handler(signal.SIGINT)
return 0
diff --git a/daemons/lvmdbusd/utils.py b/daemons/lvmdbusd/utils.py
index f5bca1b46..d24a34935 100644
--- a/daemons/lvmdbusd/utils.py
+++ b/daemons/lvmdbusd/utils.py
@@ -11,10 +11,12 @@ import xml.etree.ElementTree as Et
import sys
import inspect
import ctypes
+import errno
+import fcntl
import os
+import stat
import string
import datetime
-from fcntl import fcntl, F_GETFL, F_SETFL
import dbus
from lvmdbusd import cfg
@@ -690,8 +692,8 @@ def mt_remove_dbus_objects(objs):
# Make stream non-blocking
def make_non_block(stream):
- flags = fcntl(stream, F_GETFL)
- fcntl(stream, F_SETFL, flags | os.O_NONBLOCK)
+ flags = fcntl.fcntl(stream, fcntl.F_GETFL)
+ fcntl.fcntl(stream, fcntl.F_SETFL, flags | os.O_NONBLOCK)
def read_decoded(stream):
@@ -699,3 +701,32 @@ def read_decoded(stream):
if tmp:
return tmp.decode("utf-8")
return ''
+
+
+class LockFile(object):
+ """
+ Simple lock file class
+ Based on Pg.1144 "The Linux Programming Interface" by Michael Kerrisk
+ """
+ def __init__(self, lock_file):
+ self.fd = 0
+ self.lock_file = lock_file
+
+ def __enter__(self):
+ try:
+ self.fd = os.open(self.lock_file, os.O_CREAT | os.O_RDWR, stat.S_IRUSR | stat.S_IWUSR)
+
+ # Get and set the close on exec and lock the file
+ flags = fcntl.fcntl(self.fd, fcntl.F_GETFD)
+ flags |= fcntl.FD_CLOEXEC
+ fcntl.fcntl(self.fd, fcntl.F_SETFL, flags)
+ fcntl.lockf(self.fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
+ except OSError as e:
+ if e.errno == errno.EAGAIN:
+ log_error("Daemon already running, exiting!")
+ else:
+ log_error("Error during creation of lock file(%s): errno(%d), exiting!" % (self.lock_file, e.errno))
+ sys.exit(114)
+
+ def __exit__(self, _type, _value, _traceback):
+ os.close(self.fd)
reply other threads:[~2022-09-19 15:57 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220919155749.E9B533858C53@sourceware.org \
--to=tasleson@sourceware.org \
--cc=lvm-devel@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.