[master 3/5] Add dynamic mountpoint detection support

vojtechtrefny installerbot-noreply at redhat.com
Mon Mar 16 12:29:00 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/devicetree.py       |  14 +++++
 blivet/formats/__init__.py |   1 +
 blivet/formats/fs.py       |  15 ++++-
 blivet/mounts.py           | 137 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 166 insertions(+), 1 deletion(-)
 create mode 100644 blivet/mounts.py

diff --git a/blivet/devicetree.py b/blivet/devicetree.py
index 75f00d0..4a079ac 100644
--- a/blivet/devicetree.py
+++ b/blivet/devicetree.py
@@ -50,6 +50,7 @@
 from .devicelibs import edd
 from . import udev
 from . import util
+from . import mounts
 from .platform import platform
 from . import tsort
 from .flags import flags
@@ -95,6 +96,9 @@ def __init__(self, conf=None, passphrase=None, luksDict=None,
             :type dasd: :class:`~.dasd.DASD`
 
         """
+
+        self.mountsCache = mounts.MountsCache()
+
         self.reset(conf, passphrase, luksDict, iscsi, dasd)
 
     def reset(self, conf=None, passphrase=None, luksDict=None,
@@ -1715,6 +1719,10 @@ def handleBTRFSFormat(self, info, device):
                                           exists=True)
             self._addDevice(btrfs_dev)
 
+        btrfs_dev.format.mountsCache = self.mountsCache
+        btrfs_dev.originalFormat.mountsCache = self.mountsCache
+        self.mountsCache.add(btrfs_dev.format.device, btrfs_dev.format.subvolspec)
+
         if not btrfs_dev.subvolumes:
             snapshots = btrfs_dev.listSubVolumes(snapshotsOnly=True)
             snapshot_ids = [s["id"] for s in snapshots]
@@ -1754,6 +1762,9 @@ def handleBTRFSFormat(self, info, device):
                                       exists=True)
                 self._addDevice(subvol)
 
+                subvol.format.mountsCache = self.mountsCache
+                self.mountsCache.add(subvol.format.device, subvol.format.subvolspec)
+
     def handleUdevDeviceFormat(self, info, device):
         log_method_call(self, name=getattr(device, "name", None))
 
@@ -1885,6 +1896,9 @@ def handleUdevDeviceFormat(self, info, device):
             self.handleUdevLVMPVFormat(info, device)
         elif device.format.type == "btrfs":
             self.handleBTRFSFormat(info, device)
+        else:
+            device.format.mountsCache = self.mountsCache
+            self.mountsCache.add(device.format.device)
 
     def updateDeviceFormat(self, device):
         log.info("updating format of device: %s", device)
diff --git a/blivet/formats/__init__.py b/blivet/formats/__init__.py
index 0b84528..605c95f 100644
--- a/blivet/formats/__init__.py
+++ b/blivet/formats/__init__.py
@@ -160,6 +160,7 @@ class DeviceFormat(ObjectID):
     _check = False
     _hidden = False                     # hide devices with this formatting?
     _ksMountpoint = None
+    mountsCache = None
 
     def __init__(self, **kwargs):
         """
diff --git a/blivet/formats/fs.py b/blivet/formats/fs.py
index 9c7353a..935b5ed 100644
--- a/blivet/formats/fs.py
+++ b/blivet/formats/fs.py
@@ -110,7 +110,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 +581,13 @@ def loadModule(self):
         # also need to update the list of supported filesystems.
         update_kernel_filesystems()
 
+    @property
+    def systemMountpoint(self):
+        if not self.mountsCache:
+            return None
+
+        return self.mountsCache.getMountpoint(self.device)
+
     def testMount(self):
         """ Try to mount the fs and return True if successful. """
         ret = False
@@ -1160,6 +1166,13 @@ def setup(self, **kwargs):
 
         return self.mount(**kwargs)
 
+    @property
+    def systemMountpoint(self):
+        if not self.mountsCache:
+            return None
+
+        return self.mountsCache.getMountpoint(self.device, self.subvolspec)
+
 register_device_format(BTRFS)
 
 
diff --git a/blivet/mounts.py b/blivet/mounts.py
new file mode 100644
index 0000000..33b3bf9
--- /dev/null
+++ b/blivet/mounts.py
@@ -0,0 +1,137 @@
+# 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 = {}
+
+        # new device manually added to cache since last check
+        self.newDevice = False
+
+    def add(self, devspec, subvolspec=None):
+        """ Add device to cache
+
+            :param devscpec: device specification, eg. "/dev/vda1"
+            :type devspec: str
+            :param subvolspec: btrfs subvolume specification, eg. ID or name
+            :type subvolspec: str
+
+        """
+
+        self.mountpoints[(devspec, subvolspec)] = None
+        self.newDevice = True
+
+    def remove(self, devspec, subvolspec=None):
+        """ Remove device from cache
+
+            :param devscpec: device specification, eg. "/dev/vda1"
+            :type devspec: str
+            :param subvolspec: btrfs subvolume specification, eg. ID or name
+            :type subvolspec: str
+
+        """
+
+        if (devspec, subvolspec) in self.mountpoints:
+            del self.mountpoints[(devspec, subvolspec)]
+
+    def clear(self):
+        """ Clear cache
+        """
+
+        for key in self.mountpoints.keys():
+            self.mountpoints[key] = None
+
+        self._getActiveMounts()
+
+    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
+
+        """
+
+        self._cacheCheck()
+
+        if (devspec, subvolspec) not in self.mountpoints.keys():
+            return None
+
+        else:
+            return self.mountpoints[(devspec, subvolspec)]
+
+    def _getActiveMounts(self):
+
+        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
+
+                        fmt = self._resolveFormat(devspec, subvolspec)
+
+            else:
+                fmt = self._resolveFormat(devspec)
+
+            if fmt:
+                self.mountpoints[fmt] = mountpoint
+
+    def _resolveFormat(self, devspec, subvolspec=None):
+
+        for fmt in self.mountpoints.keys():
+            if fmt[0] == devspec:
+                if not fmt[1]:
+                    return fmt
+
+                elif fmt[1] == subvolspec:
+                    return fmt
+
+    def _cacheCheck(self):
+
+        md5hash = util.md5_file("/proc/mounts")
+
+        if md5hash != self.mountsHash or self.newDevice:
+            self.newDevice = False
+            self.mountsHash = md5hash
+            self.clear()


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


More information about the anaconda-patches mailing list