From f34429036800574328097bb957d6c493bd5d7260 Mon Sep 17 00:00:00 2001
From: Bob Lantz <rlantz@cs.stanford.edu>
Date: Sun, 7 Jul 2013 15:27:49 -0700
Subject: [PATCH] Change API for more efficient remount and unmount.

---
 examples/bind.py | 72 ++++++++++++++++++++++++++++++++++--------------
 1 file changed, 51 insertions(+), 21 deletions(-)

diff --git a/examples/bind.py b/examples/bind.py
index 142eec40..d4d28a44 100755
--- a/examples/bind.py
+++ b/examples/bind.py
@@ -7,17 +7,20 @@
 """
 
 from mininet.net import Mininet
-from mininet.node import Host, Switch, Controller
+from mininet.node import Host
 from mininet.cli import CLI
 from mininet.util import errFail, quietRun, errRun
 from mininet.topo import SingleSwitchTopo
 from mininet.log import setLogLevel, info, debug
 
-from os.path import join, realpath
+from os.path import realpath
 from functools import partial
 
+
 # Utility functions for unmounting a tree
 
+MNRUNDIR = realpath( '/var/run/mn' )
+
 def mountPoints():
     "Return list of mounted file systems"
     mtab, _err, _ret = errFail( 'cat /proc/mounts' )
@@ -31,7 +34,7 @@ def mountPoints():
         mounts.append( mount )
     return mounts
 
-def unmountAll( dir='/var/run/mn' ):
+def unmountAll( dir=MNRUNDIR ):
     "Unmount all mounts under a directory tree"
     dir = realpath( dir )
     # Find all mounts below dir
@@ -53,11 +56,17 @@ def unmountAll( dir='/var/run/mn' ):
 class HostWithPrivateDirs( Host ):
     "Host with private directories"
 
-    mnRunDir = realpath( '/var/run/mn' )
+    mnRunDir = MNRUNDIR
 
     def __init__(self, name, *args, **kwargs ):
-        "privateDirs: list of private directories"
+        """privateDirs: list of private directories
+           remounts: dirs to remount
+           unmount: unmount dirs in cleanup? (True)
+           Note: if unmount is False, you must call unmountAll()
+           manually."""
         self.privateDirs = kwargs.pop( 'privateDirs', [] )
+        self.remounts = kwargs.pop( 'remounts', [] )
+        self.unmount = kwargs.pop( 'unmount', True )
         Host.__init__( self, name, *args, **kwargs )
         self.rundir = '%s/%s' % ( self.mnRunDir, name )
         if self.privateDirs:
@@ -86,19 +95,28 @@ def mountPrivateDirs( self ):
             errFail( 'mount -B %s %s' %
                            ( privateDir, mountPoint) )
 
-    def remountDirs( self, fstypes=[ 'nfs' ] ):
-        "Remount mounted file systems"
-        dirs = self.cmd( 'cat /proc/mounts' ).strip().split( '\n' )
+    def mountDirs( self, dirs ):
+        "Mount a list of directories"
+        for dir in dirs:
+            mountpoint = self.root + dir
+            errFail( 'mount -B %s %s' %
+                     ( dir, mountpoint ) )
+
+    @classmethod
+    def findRemounts( cls, fstypes=[ 'nfs' ] ):
+        """Identify mount points in /proc/mounts to remount
+           fstypes: file system types to match"""
+        dirs = quietRun( 'cat /proc/mounts' ).strip().split( '\n' )
+        remounts = []
         for dir in dirs:
             line = dir.split()
             mountpoint, fstype = line[ 1 ], line[ 2 ]
             # Don't re-remount directories!!!
-            if mountpoint.find( self.mnRunDir ) == 0:
+            if mountpoint.find( cls.mnRunDir ) == 0:
                 continue
             if fstype in fstypes:
-                print "remounting:", mountpoint
-                errFail( 'mount -B %s %s' % (
-                         mountpoint, self.root + mountpoint ) )
+                remounts.append( mountpoint )
+        return remounts
 
     def createBindMounts( self ):
         """Create a chroot directory structure,
@@ -113,7 +131,7 @@ def createBindMounts( self ):
         # Recursively mount / in private doort
         # note we'll remount /sys and /proc later
         errFail( 'mount -B / ' + self.root )
-        self.remountDirs()
+        self.mountDirs( self.remounts )
         self.mountPrivateDirs()
 
     def unmountBindMounts( self ):
@@ -131,33 +149,45 @@ def popen( self, *args, **kwargs ):
         return Host.popen( self, *args, **kwargs )
 
     def cleanup( self ):
-        "Clean up, then unmount bind mounts"
+        """Clean up, then unmount bind mounts
+           unmount: actually unmount bind mounts?"""
         # Wait for process to actually terminate
         self.shell.wait()
         Host.cleanup( self )
-        self.unmountBindMounts()
-        errFail( 'rmdir ' + self.root )
+        if self.unmount:
+            self.unmountBindMounts()
+            errFail( 'rmdir ' + self.root )
+
+
+# Convenience aliases
+
+findRemounts = HostWithPrivateDirs.findRemounts
+
 
 # Sample usage
 
 def testHostWithPrivateDirs():
     "Test bind mounts"
-    topo = SingleSwitchTopo( 2 )
+    topo = SingleSwitchTopo( 10 )
+    remounts = findRemounts( fstypes=[ 'nfs' ] )
     privateDirs = [ '/var/log', '/var/run' ]
-    host = partial( HostWithPrivateDirs, privateDirs=privateDirs )
+    host = partial( HostWithPrivateDirs, remounts=remounts,
+                    privateDirs=privateDirs, unmount=False )
     net = Mininet( topo=topo, host=host )
     net.start()
-    print 'Private Directories:', privateDirs
+    info( 'Private Directories:', privateDirs, '\n' )
     CLI( net )
     net.stop()
+    # We do this all at once to save a bit of time
+    info( 'Unmounting host bind mounts...\n' )
+    unmountAll()
 
 
 if __name__ == '__main__':
     unmountAll()
     setLogLevel( 'info' )
     testHostWithPrivateDirs()
-    unmountAll()
-
+    info( 'Done.\n')
 
 
 
-- 
GitLab