Change in vdsm[master]: mounts: Optimize mount loop device resolution
dkuznets at redhat.com
dkuznets at redhat.com
Wed Jun 11 08:22:44 UTC 2014
Dima Kuznetsov has uploaded a new change for review.
Change subject: mounts: Optimize mount loop device resolution
......................................................................
mounts: Optimize mount loop device resolution
Existing code was re-reading mtab for each /proc/mounts entry.
Added lookup dictionary that translates /dev/loop spec to actual file
spec.
Change-Id: I54f11786b45782cedd994d52e1e506292132fa47
Signed-off-by: Dima Kuznetsov <dkuznets at redhat.com>
---
M tests/mountTests.py
M vdsm/storage/mount.py
2 files changed, 100 insertions(+), 10 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/86/28586/1
diff --git a/tests/mountTests.py b/tests/mountTests.py
index 04aa753..81831e9 100644
--- a/tests/mountTests.py
+++ b/tests/mountTests.py
@@ -20,8 +20,10 @@
from contextlib import contextmanager
import errno
-from tempfile import mkstemp
+from tempfile import mkstemp, mkdtemp
import os
+import shutil
+import stat
from nose.plugins.skip import SkipTest
@@ -30,6 +32,7 @@
from storage.misc import execCmd
import storage.mount as mount
from testValidation import checkSudo
+import monkeypatch
FLOPPY_SIZE = (2 ** 20) * 4
@@ -72,3 +75,75 @@
self.assertTrue(m.isMounted())
finally:
m.umount()
+
+
+class IterMountsPerfTests(TestCaseBase):
+
+ @classmethod
+ def _createFiles(cls, path, size):
+ mounts_path = os.path.join(path, 'mounts')
+ mtab_path = os.path.join(path, 'mtab')
+
+ line_fmt = ('%(fs_spec)s\t%(fs_file)s\t%(fs_vfstype)s'
+ '\t%(fs_mntops)s\t%(fs_freq)s\t%(fs_passno)s\n')
+
+ with open(mounts_path, 'w') as mounts, open(mtab_path, 'w') as mtab:
+ for i in xrange(100):
+ mnt = mount.MountRecord('/dev/sda%d' % i,
+ '/some/path/%d' % i,
+ 'btrfs',
+ 'rw,relatime',
+ '0', '0')
+ mounts.write(line_fmt % mnt._asdict())
+ mtab.write(line_fmt % mnt._asdict())
+
+ for i in xrange(size):
+ mounts_mnt = mount.MountRecord('/dev/loop%d' % i,
+ '/mnt/loop%d' % i,
+ 'xfs',
+ 'rw,foobar,errors=continue',
+ '0', '0')
+ mtab_mnt = mount.MountRecord('/images/loop%d.img' % i,
+ '/mnt/loop%d' % i,
+ 'xfs',
+ 'rw,loop=/dev/loop%d' % i,
+ '0', '0')
+ mounts.write(line_fmt % mounts_mnt._asdict())
+ mtab.write(line_fmt % mtab_mnt._asdict())
+
+ return (mounts_path, mtab_path)
+
+ def setUp(self):
+ self._temp_dir = mkdtemp()
+ mounts, mtab = self._createFiles(self._temp_dir, 1000)
+ old_stat = os.stat
+
+ def mock_stat(path):
+ if path.startswith('/dev/loop'):
+ return old_stat('/')
+ return old_stat(path)
+ self._patch = monkeypatch.Patch([(mount, '_PROC_MOUNTS_PATH', mounts),
+ (mount, '_ETC_MTAB_PATH', mtab),
+ (mount, '_SYS_DEV_BLOCK_PATH',
+ self._temp_dir),
+ (mount, '_loopLookup', {}),
+ (os, 'stat', mock_stat),
+ (stat, 'S_ISBLK', lambda x: True)])
+ self._patch.apply()
+
+ def tearDown(self):
+ shutil.rmtree(self._temp_dir)
+ self._patch.revert()
+
+ def test1000EntriesValidate(self):
+ mounts = list(mount.iterMounts())
+ for entry in mounts:
+ mountpoint = entry.fs_file
+ if mountpoint.startswith('/mnt/loop'):
+ expected_spec = ('/images/loop%s.img' %
+ mountpoint[len('/mnt/loop'):])
+ self.assertEquals(entry.fs_spec, expected_spec)
+
+ def test1000EntriesTwice(self):
+ list(mount.iterMounts())
+ list(mount.iterMounts())
diff --git a/vdsm/storage/mount.py b/vdsm/storage/mount.py
index 1671bf8..4fd356f 100644
--- a/vdsm/storage/mount.py
+++ b/vdsm/storage/mount.py
@@ -36,6 +36,10 @@
MountRecord = namedtuple("MountRecord", "fs_spec fs_file fs_vfstype "
"fs_mntops fs_freq fs_passno")
+_ETC_MTAB_PATH = '/etc/mtab/'
+_PROC_MOUNTS_PATH = '/proc/mounts'
+_SYS_DEV_BLOCK_PATH = '/sys/dev/block/'
+
_RE_ESCAPE = re.compile(r"\\0\d\d")
@@ -62,7 +66,7 @@
def _iterateMtab():
- with open("/etc/mtab", "r") as f:
+ with open(_ETC_MTAB_PATH, "r") as f:
for line in f:
yield _parseFstabLine(line)
@@ -73,6 +77,9 @@
class MountError(RuntimeError):
pass
+
+
+_loopLookup = {}
def _resolveLoopDevice(path):
@@ -93,7 +100,9 @@
minor = os.minor(st.st_rdev)
major = os.major(st.st_rdev)
- loopdir = "/sys/dev/block/%d:%d/loop" % (major, minor)
+ loopdir = os.path.join(_SYS_DEV_BLOCK_PATH,
+ '%d:%d' % (major, minor),
+ 'loop')
if os.path.exists(loopdir):
with open(loopdir + "/backing_file", "r") as f:
# Remove trailing newline
@@ -101,24 +110,30 @@
# 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
+ if not _loopLookup:
+ for entry in _iterateMtab():
+ for opt in entry.fs_mntops:
+ if opt.startswith('loop='):
+ _loopLookup[opt[len('loop='):]] = entry.fs_spec
- return rec.fs_spec
+ # In case there were not entries above, make sure we
+ # don't do this again
+ _loopLookup[True] = True
+
+ if path in _loopLookup:
+ return _loopLookup[path]
return path
def _iterKnownMounts():
- with open("/proc/mounts", "r") as f:
+ with open(_PROC_MOUNTS_PATH, "r") as f:
for line in f:
yield _parseFstabLine(line)
def _iterMountRecords():
+
for rec in _iterKnownMounts():
realSpec = _resolveLoopDevice(rec.fs_spec)
if rec.fs_spec == realSpec:
--
To view, visit http://gerrit.ovirt.org/28586
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I54f11786b45782cedd994d52e1e506292132fa47
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Dima Kuznetsov <dkuznets at redhat.com>
More information about the vdsm-patches
mailing list