[master 3/6] Add dynamic mountpoint detection support

vojtechtrefny installerbot-noreply at redhat.com
Wed Mar 18 15:45:29 UTC 2015


From: Vojtech Trefny <vtrefny at redhat.com>

Current format._mountpoint attribute for "active" mountpoints is
being replaced with property format.systemMountpoint that returns
current mountpoint based on system information (cached information
from /proc/mounts and /proc/self/mountinfo)

Signed-off-by: Vojtech Trefny <vtrefny at redhat.com>
---
 blivet/formats/fs.py | 48 +++++++++++++++++------------
 blivet/mounts.py     | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 116 insertions(+), 19 deletions(-)
 create mode 100644 blivet/mounts.py

diff --git a/blivet/formats/fs.py b/blivet/formats/fs.py
index 9c7353a..4450c06 100644
--- a/blivet/formats/fs.py
+++ b/blivet/formats/fs.py
@@ -39,6 +39,7 @@
 from ..size import B, KiB, MiB, GiB, KB, MB, GB
 from ..i18n import _, N_
 from .. import udev
+from ..mounts import mountsCache
 
 import logging
 log = logging.getLogger("blivet")
@@ -110,7 +111,6 @@ def __init__(self, **kwargs):
         # filesystem size does not necessarily equal device size
         self._size = kwargs.get("size", Size(0))
         self._minInstanceSize = Size(0)    # min size of this FS instance
-        self._mountpoint = None     # the current mountpoint when mounted
 
         # Resize operations are limited to error-free filesystems whose current
         # size is known.
@@ -582,6 +582,13 @@ def loadModule(self):
         # also need to update the list of supported filesystems.
         update_kernel_filesystems()
 
+    @property
+    def systemMountpoint(self):
+        if not self.exists:
+            return None
+
+        return mountsCache.getMountpoint(self.device)
+
     def testMount(self):
         """ Try to mount the fs and return True if successful. """
         ret = False
@@ -665,29 +672,25 @@ def mount(self, options="", chroot="/", mountpoint=None):
             if not ret:
                 log.warning("Failed to set SELinux context for newly mounted filesystem lost+found directory at %s to %s", lost_and_found_path, lost_and_found_context)
 
-        self._mountpoint = chrootedMountpoint
-
     def unmount(self):
         """ Unmount this filesystem. """
         if not self.exists:
             raise FSError("filesystem has not been created")
 
-        if not self._mountpoint:
+        if not self.systemMountpoint:
             # not mounted
             return
 
-        if not os.path.exists(self._mountpoint):
+        if not os.path.exists(self.systemMountpoint):
             raise FSError("mountpoint does not exist")
 
         udev.settle()
-        rc = util.umount(self._mountpoint)
+        rc = util.umount(self.systemMountpoint)
         if rc:
             # try and catch whatever is causing the umount problem
-            util.run_program(["lsof", self._mountpoint])
+            util.run_program(["lsof", self.systemMountpoint])
             raise FSError("umount failed")
 
-        self._mountpoint = None
-
     def readLabel(self):
         """Read this filesystem's label.
 
@@ -900,7 +903,7 @@ def status(self):
         # FIXME check /proc/mounts or similar
         if not self.exists:
             return False
-        return self._mountpoint is not None
+        return self.systemMountpoint is not None
 
     def sync(self, root="/"):
         pass
@@ -1160,6 +1163,13 @@ def setup(self, **kwargs):
 
         return self.mount(**kwargs)
 
+    @property
+    def systemMountpoint(self):
+        if not self.exists:
+            return None
+
+        return mountsCache.getMountpoint(self.device, self.subvolspec)
+
 register_device_format(BTRFS)
 
 
@@ -1272,16 +1282,16 @@ def sync(self, root='/'):
             This is a little odd because xfs_freeze will only be
             available under the install root.
         """
-        if not self.status or not self._mountpoint.startswith(root):
+        if not self.status or not self.systemMountpoint.startswith(root):
             return
 
         try:
-            util.run_program(["xfs_freeze", "-f", self.mountpoint], root=root)
+            util.run_program(["xfs_freeze", "-f", self.systemMountpoint], root=root)
         except OSError as e:
             log.error("failed to run xfs_freeze: %s", e)
 
         try:
-            util.run_program(["xfs_freeze", "-u", self.mountpoint], root=root)
+            util.run_program(["xfs_freeze", "-u", self.systemMountpoint], root=root)
         except OSError as e:
             log.error("failed to run xfs_freeze: %s", e)
 
@@ -1605,14 +1615,14 @@ def _setOptions(self, options):
 
     @property
     def free(self):
-        if self._mountpoint:
-            # If self._mountpoint is defined, it means this tmpfs mount
+        if self.systeMountpoint:
+            # If self.systeMountpoint is defined, it means this tmpfs mount
             # has been mounted and there is a path we can use as a handle to
             # look-up the free space on the filesystem.
             # When running with changeroot, such as during installation,
-            # self._mountpoint is set to the full changeroot path once mounted,
-            # so even with changeroot, statvfs should still work fine.
-            st = os.statvfs(self._mountpoint)
+            # self.systeMountpoint is set to the full changeroot path once
+            # mounted so even with changeroot, statvfs should still work fine.
+            st = os.statvfs(self.systeMountpoint)
             free_space = Size(st.f_bavail*st.f_frsize)
         else:
             # Free might be called even if the tmpfs mount has not been
@@ -1646,7 +1656,7 @@ def resizeArgs(self):
         # if any mount options are defined, append them
         if self._options:
             remount_options = "%s,%s" % (remount_options, self._options)
-        return ['-o', remount_options, self._type, self._mountpoint]
+        return ['-o', remount_options, self._type, self.systeMountpoint]
 
     def doResize(self):
         # we need to override doResize, because the
diff --git a/blivet/mounts.py b/blivet/mounts.py
new file mode 100644
index 0000000..80c95b4
--- /dev/null
+++ b/blivet/mounts.py
@@ -0,0 +1,87 @@
+# mounts.py
+# Active mountpoints cache.
+#
+# Copyright (C) 2015  Red Hat, Inc.
+#
+# 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, or (at your option) any later version.
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY expressed or implied, including the implied warranties of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+# Public License for more details.  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.  Any Red Hat trademarks that are incorporated in the
+# source code or documentation are not subject to the GNU General Public
+# License and may only be used or replicated with the express permission of
+# Red Hat, Inc.
+#
+# Red Hat Author(s): Vojtech Trefny <vtrefny at redhat.com>
+#
+
+from . import util
+
+import logging
+log = logging.getLogger("blivet")
+
+class MountsCache(object):
+
+    def __init__(self):
+        self.mountsHash = 0
+        self.mountpoints = {}
+
+    def getMountpoint(self, devspec, subvolspec=None):
+        """ Get mountpoint for selected device
+
+            :param devscpec: device specification, eg. "/dev/vda1"
+            :type devspec: str
+            :param subvolspec: btrfs subvolume specification, eg. ID or name
+            :type subvolspec: str
+            :returns: mountpoint (path)
+            :rtype: str or NoneType
+
+        """
+
+        self._cacheCheck()
+
+        return self.mountpoints.get((devspec, subvolspec))
+
+    def _getActiveMounts(self):
+        """ Get information about mounted devices from /proc/mounts and
+            /proc/self/mountinfo
+        """
+
+        for line in open("/proc/mounts").readlines():
+            try:
+                (devspec, mountpoint, fstype, options, _rest) = line.split(None, 4)
+            except ValueError:
+                log.error("failed to parse /proc/mounts line: %s", line)
+                continue
+
+            if fstype == "btrfs":
+                # get the subvol name from /proc/self/mountinfo
+                for line in open("/proc/self/mountinfo").readlines():
+                    fields = line.split()
+                    _subvol = fields[3]
+                    _mountpoint = fields[4]
+                    _devspec = fields[9]
+                    if _mountpoint == mountpoint and _devspec == devspec:
+                        # empty _subvol[1:] means it is a top-level volume
+                        subvolspec = _subvol[1:] or 5
+
+                        self.mountpoints[(devspec, subvolspec)] = mountpoint
+
+            else:
+                self.mountpoints[(devspec, None)] = mountpoint
+
+    def _cacheCheck(self):
+
+        md5hash = util.md5_file("/proc/mounts")
+
+        if md5hash != self.mountsHash:
+            self.mountsHash = md5hash
+            self.mountpoints = {}
+            self._getActiveMounts()
+
+mountsCache = MountsCache()


-- 
To view this commit on github, visit https://github.com/rhinstaller/blivet/commit/6ca637ed56de7aea7f4ecf8669186e712fae1556


More information about the anaconda-patches mailing list