Gentoo Archives: gentoo-catalyst

From: Matt Turner <mattst88@g.o>
To: gentoo-catalyst@l.g.o
Cc: Matt Turner <mattst88@g.o>
Subject: [gentoo-catalyst] [PATCH 03/12] catalyst: Use libmount for handling mounts
Date: Thu, 29 Oct 2020 16:16:43
Message-Id: 20201029161632.146732-3-mattst88@gentoo.org
In Reply to: [gentoo-catalyst] [PATCH 01/12] catalyst: Replace pathcompare() by Matt Turner
1 Handle the mounts/unmounts in all in process rather than shelling out
2 (pun intended!) to an external program.
3
4 While we're here, change some log.notice to log.debug since those cases
5 are normal and expected.
6
7 Signed-off-by: Matt Turner <mattst88@g.o>
8 ---
9 catalyst/base/stagebase.py | 57 +++++++++++++++++++++++---------------
10 1 file changed, 35 insertions(+), 22 deletions(-)
11
12 diff --git a/catalyst/base/stagebase.py b/catalyst/base/stagebase.py
13 index e71ce344..73eacfbe 100644
14 --- a/catalyst/base/stagebase.py
15 +++ b/catalyst/base/stagebase.py
16 @@ -6,6 +6,7 @@ import sys
17
18 from pathlib import Path
19
20 +import libmount
21 import toml
22
23 from snakeoil import fileutils
24 @@ -853,7 +854,8 @@ class StageBase(TargetBase, ClearBase, GenBase):
25
26 source = str(self.mount[x]['source'])
27 target = self.settings['chroot_path'] + str(self.mount[x]['target'])
28 - mount = ['mount']
29 + fstype = ''
30 + options = ''
31
32 log.debug('bind %s: "%s" -> "%s"', x, source, target)
33
34 @@ -861,18 +863,20 @@ class StageBase(TargetBase, ClearBase, GenBase):
35 if 'var_tmpfs_portage' not in self.settings:
36 continue
37
38 - mount += ['-t', 'tmpfs', '-o',
39 - f"size={self.settings['var_tmpfs_portage']}G"]
40 + fstype = 'tmpfs'
41 + options = f"size={self.settings['var_tmpfs_portage']}G"
42 elif source == 'tmpfs':
43 - mount += ['-t', 'tmpfs']
44 + fstype = 'tmpfs'
45 elif source == 'shm':
46 - mount += ['-t', 'tmpfs', '-o', 'noexec,nosuid,nodev']
47 + fstype = 'tmpfs'
48 + options = 'noexec,nosuid,nodev'
49 else:
50 source_path = Path(self.mount[x]['source'])
51 if source_path.suffix == '.sqfs':
52 - mount += ['-o', 'ro']
53 + fstype = 'squashfs'
54 + options = 'ro,loop'
55 else:
56 - mount.append('--bind')
57 + options = 'bind'
58
59 # We may need to create the source of the bind mount. E.g., in the
60 # case of an empty package cache we must create the directory that
61 @@ -881,38 +885,47 @@ class StageBase(TargetBase, ClearBase, GenBase):
62
63 Path(target).mkdir(mode=0o755, parents=True, exist_ok=True)
64
65 - cmd(mount + [source, target], env=self.env, fail_func=self.unbind)
66 + try:
67 + cxt = libmount.Context(source=source, target=target,
68 + fstype=fstype, options=options)
69 + cxt.mount()
70 + except OSError as e:
71 + self.unbind()
72 + raise CatalystError(f"Couldn't mount: {source}, {e.strerror}")
73
74 def unbind(self):
75 - ouch = 0
76 - mypath = self.settings["chroot_path"]
77 + chroot_path = self.settings["chroot_path"]
78 + umount_failed = False
79
80 # Unmount in reverse order
81 - for x in [x for x in reversed(self.mount) if self.mount[x]['enable']]:
82 - target = normpath(mypath + self.mount[x]['target'])
83 - if not os.path.exists(target):
84 - log.notice('%s does not exist. Skipping', target)
85 + for target in [Path(chroot_path + self.mount[x]['target'])
86 + for x in reversed(self.mount)
87 + if self.mount[x]['enable']]:
88 + if not target.exists():
89 + log.debug('%s does not exist. Skipping', target)
90 continue
91
92 if not ismount(target):
93 - log.notice('%s is not a mount point. Skipping', target)
94 + log.debug('%s is not a mount point. Skipping', target)
95 continue
96
97 try:
98 - cmd(['umount', target], env=self.env)
99 - except CatalystError:
100 + cxt = libmount.Context(target=str(target))
101 + cxt.umount()
102 + except OSError:
103 log.warning('First attempt to unmount failed: %s', target)
104 log.warning('Killing any pids still running in the chroot')
105
106 self.kill_chroot_pids()
107
108 try:
109 - cmd(['umount', target], env=self.env)
110 - except CatalystError:
111 - ouch = 1
112 - log.warning("Couldn't umount bind mount: %s", target)
113 + cxt.umount()
114 + except OSError as e:
115 + umount_failed = True
116 + log.warning("Couldn't umount: %s, %s", target,
117 + e.strerror)
118
119 - if ouch:
120 + if umount_failed:
121 # if any bind mounts really failed, then we need to raise
122 # this to potentially prevent an upcoming bash stage cleanup script
123 # from wiping our bind mounts.
124 --
125 2.26.2