Change in vdsm[master]: mount: Improve loop devices resolving

nsoffer at redhat.com nsoffer at redhat.com
Sun May 25 19:30:05 UTC 2014


Nir Soffer has uploaded a new change for review.

Change subject: mount: Improve loop devices resolving
......................................................................

mount: Improve loop devices resolving

_resolveLoopDevice() used O(n^2) search for resolving loop device
backing file. For every block device in /proc/mounts, it read and parsed
all lines of /etc/mtab, even all platforms where /etc/mtab contains not
additional info.

This patch changes the search so /etc/mtab is read and parsed once only
on platforms where it is different from /proc/mounts. On these
platforms, we can get the loop device backing file from /etc/mtab. On
platforms where /etc/mtab is a symlink to /proc/self/mounts, we get the
backing file from /sys/block/loop*/loop/backing_file.

The new code assumes that loop devices are named /dev/loop*, which
simplifes the code for resolving the backing file.

Change-Id: I40c0bd772327248e6fe08189dada043ea1c6c080
Relates-to: https://bugzilla.redhat.com/1099856
Signed-off-by: Nir Soffer <nsoffer at redhat.com>
---
M vdsm/storage/mount.py
1 file changed, 35 insertions(+), 53 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/90/28090/1

diff --git a/vdsm/storage/mount.py b/vdsm/storage/mount.py
index 1671bf8..cc633bf 100644
--- a/vdsm/storage/mount.py
+++ b/vdsm/storage/mount.py
@@ -22,7 +22,6 @@
 from os.path import normpath
 import re
 import os
-import stat
 
 from vdsm import constants
 import misc
@@ -32,6 +31,11 @@
 VFS_NFS = "nfs"
 VFS_NFS4 = "nfs4"
 VFS_EXT3 = "ext3"
+
+# Mounts sources
+
+PROC_MOUNTS = '/proc/mounts'
+ETC_MTAB = '/etc/mtab'
 
 MountRecord = namedtuple("MountRecord", "fs_spec fs_file fs_vfstype "
                          "fs_mntops fs_freq fs_passno")
@@ -61,12 +65,6 @@
                        fs_freq, fs_passno)
 
 
-def _iterateMtab():
-    with open("/etc/mtab", "r") as f:
-        for line in f:
-            yield _parseFstabLine(line)
-
-
 def _parseFstabPath(path):
     return _RE_ESCAPE.sub(lambda s: chr(int(s.group()[1:], 8)), path)
 
@@ -75,58 +73,42 @@
     pass
 
 
-def _resolveLoopDevice(path):
-    """
-    Loop devices appear as the loop device under /proc/mount instead of the
-    backing file. As the mount command does the resolution so must we.
-    """
-    if not path.startswith("/"):
-        return path
-
-    try:
-        st = os.stat(path)
-    except:
-        return path
-
-    if not stat.S_ISBLK(st.st_mode):
-        return path
-
-    minor = os.minor(st.st_rdev)
-    major = os.major(st.st_rdev)
-    loopdir = "/sys/dev/block/%d:%d/loop" % (major, minor)
-    if os.path.exists(loopdir):
-        with open(loopdir + "/backing_file", "r") as f:
-            # Remove trailing newline
-            return f.read()[:-1]
-
-    # Old kernels might not have the sysfs entry, this is a bit slower and does
-    # not work on hosts that do support the above method.
-    for rec in _iterateMtab():
-        loopOpt = "loop=%s" % path
-        for opt in rec.fs_mntops:
-            if opt != loopOpt:
-                continue
-
-            return rec.fs_spec
-
-    return path
+def _readLoopDeviceBackingFile(device):
+    device_name = device[len('/dev/'):]
+    path = '/sys/block/%s/loop/backing_file' % device_name
+    with open(path) as f:
+        return f.readline().rstrip()
 
 
-def _iterKnownMounts():
-    with open("/proc/mounts", "r") as f:
+def _readMountRecords(path):
+    records = {}
+    with open(path) as f:
         for line in f:
-            yield _parseFstabLine(line)
+            rec = _parseFstabLine(line)
+            records[rec.fs_file] = rec
+    return records
 
 
 def _iterMountRecords():
-    for rec in _iterKnownMounts():
-        realSpec = _resolveLoopDevice(rec.fs_spec)
-        if rec.fs_spec == realSpec:
-            yield rec
-            continue
-
-        yield MountRecord(realSpec, rec.fs_file, rec.fs_vfstype,
-                          rec.fs_mntops, rec.fs_freq, rec.fs_passno)
+    mounts = _readMountRecords(PROC_MOUNTS)
+    if not os.path.samefile(ETC_MTAB, PROC_MOUNTS):
+        mtab = _readMountRecords(ETC_MTAB)
+    else:
+        mtab = None
+    for mountpoint, rec in mounts.iteritems():
+        if rec.fs_spec.startswith('/dev/loop'):
+            if mtab:
+                fs_spec = mtab[mountpoint].fs_spec
+            else:
+                try:
+                    fs_spec = _readLoopDeviceBackingFile(rec.fs_spec)
+                except IOError as e:
+                    if e.errno != errno.ENOENT:
+                        raise
+                    fs_spec = rec.fs_spec
+            yield MountRecord(fs_spec, rec.fs_file, rec.fs_vfstype,
+                              rec.fs_mntops, rec.fs_freq, rec.fs_passno)
+        yield rec
 
 
 def iterMounts():


-- 
To view, visit http://gerrit.ovirt.org/28090
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I40c0bd772327248e6fe08189dada043ea1c6c080
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Nir Soffer <nsoffer at redhat.com>


More information about the vdsm-patches mailing list