Skip to content

Commit

Permalink
Add dynamic mountpoint detection support
Browse files Browse the repository at this point in the history
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@redhat.com>
  • Loading branch information
vojtechtrefny committed Mar 16, 2015
1 parent ba14eb9 commit f8d29e6
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 1 deletion.
14 changes: 14 additions & 0 deletions blivet/devicetree.py
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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))

Expand Down Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions blivet/formats/__init__.py
Expand Up @@ -160,6 +160,7 @@ class DeviceFormat(ObjectID):
_check = False
_hidden = False # hide devices with this formatting?
_ksMountpoint = None
mountsCache = None

def __init__(self, **kwargs):
"""
Expand Down
15 changes: 14 additions & 1 deletion blivet/formats/fs.py
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)


Expand Down
137 changes: 137 additions & 0 deletions 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@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()

0 comments on commit f8d29e6

Please sign in to comment.