Просмотр исходного кода

Fix os_dismount()

In some situations, during os morphing, some binaries that get called
inside the chroot, may mount aditional filesystems, as a child of some
already mounted FS. For example, some applications that require FUSE
may mount aditional kernel filesystems in /sys. This change unmounts
child filesystems before attempting to unmount parent filesystems.

This is done by looking in /proc/mounts first, sorting the mounts that
have the root filesystem as a prefix, and unmounting them in order.
Gabriel Adrian Samfira 7 лет назад
Родитель
Сommit
75ae4a0fef
2 измененных файлов с 25 добавлено и 13 удалено
  1. 2 2
      coriolis/osmorphing/manager.py
  2. 23 11
      coriolis/osmorphing/osmount/base.py

+ 2 - 2
coriolis/osmorphing/manager.py

@@ -57,7 +57,7 @@ def morph_image(origin_provider, destination_provider, connection_info,
     os_mount_tools.setup()
 
     event_manager.progress_update("Discovering and mounting OS partitions")
-    os_root_dir, other_mounted_dirs, os_root_dev = os_mount_tools.mount_os()
+    os_root_dir, os_root_dev = os_mount_tools.mount_os()
 
     osmorphing_info['os_root_dir'] = os_root_dir
     osmorphing_info['os_root_dev'] = os_root_dev
@@ -122,4 +122,4 @@ def morph_image(origin_provider, destination_provider, connection_info,
         import_os_morphing_tools.post_packages_install(packages_add)
 
     event_manager.progress_update("Dismounting OS partitions")
-    os_mount_tools.dismount_os(other_mounted_dirs + [os_root_dir])
+    os_mount_tools.dismount_os(os_root_dir)

+ 23 - 11
coriolis/osmorphing/osmount/base.py

@@ -45,7 +45,7 @@ class BaseOSMountTools(object, with_metaclass(abc.ABCMeta)):
         pass
 
     @abc.abstractmethod
-    def dismount_os(self, dirs):
+    def dismount_os(self, root_dir):
         pass
 
     def set_proxy(self, proxy_settings):
@@ -232,6 +232,15 @@ class BaseLinuxOSMountTools(BaseSSHOSMountTools):
                 ret.append(colls[0])
         return ret
 
+    def _get_mount_destinations(self):
+        mounts = self._exec_cmd(
+            "cat /proc/mounts").decode().split('\n')[:-1]
+        ret = set()
+        for line in mounts:
+            colls = line.split()
+            ret.add(colls[1])
+        return ret
+
     def _get_volume_block_devices(self):
         # NOTE: depending on the version of the worker OS, scanning for just
         # the device NAME may lead to LVM volumes getting displayed as:
@@ -255,7 +264,6 @@ class BaseLinuxOSMountTools(BaseSSHOSMountTools):
 
     def mount_os(self):
         dev_paths = []
-        other_mounted_dirs = []
         mouted_devs = self._get_mounted_devices()
 
         volume_devs = self._get_volume_block_devices()
@@ -316,8 +324,7 @@ class BaseLinuxOSMountTools(BaseSSHOSMountTools):
         if not os_root_dir:
             raise exception.OperatingSystemNotFound("root partition not found")
 
-        other_mounted_dirs.extend(
-            self._check_mount_fstab_partitions(os_root_dir))
+        self._check_mount_fstab_partitions(os_root_dir)
 
         for dir in set(dirs).intersection(['proc', 'sys', 'dev', 'run']):
             mount_dir = os.path.join(os_root_dir, dir)
@@ -328,13 +335,18 @@ class BaseLinuxOSMountTools(BaseSSHOSMountTools):
             self._exec_cmd(
                 'sudo mount -o bind /%(dir)s/ %(mount_dir)s' %
                 {'dir': dir, 'mount_dir': mount_dir})
-            other_mounted_dirs.append(mount_dir)
-
-        return os_root_dir, other_mounted_dirs, os_root_device
-
-    def dismount_os(self, dirs):
-        for dir in dirs:
-            self._exec_cmd('sudo umount %s' % dir)
+        return os_root_dir, os_root_device
+
+    def dismount_os(self, root_dir):
+        mounted_fs = self._get_mount_destinations()
+        # Sort all mounted filesystems by length. This will ensure that
+        # the first in the list is a subfolder of the next in the list,
+        # and we unmount them in the proper order
+        mounted_fs = list(reversed(sorted(mounted_fs)))
+        for d in mounted_fs:
+            if d.startswith(root_dir):
+                # mounted filesystem is a subfolder of our root_dir
+                self._exec_cmd('sudo umount %s' % d)
 
     def set_proxy(self, proxy_settings):
         url = proxy_settings.get('url')