Skip to content

Commit 94cc855

Browse files
committed
improves unmounting logic
1 parent d53a141 commit 94cc855

File tree

4 files changed

+92
-46
lines changed

4 files changed

+92
-46
lines changed

cmd/status.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ func getCurrentlyBootedPartition(a *core.ABRootManager) (string, string, error)
300300
if err != nil {
301301
return "", "", err
302302
}
303-
defer bootPart.Unmount()
303+
defer core.UnmountRecursive(tmpBootMount, 0)
304304

305305
g, err := core.NewGrub(bootPart)
306306
if err != nil {

core/chroot.go

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -93,32 +93,12 @@ func NewChroot(root string, rootUuid string, rootDevice string, mountUserEtc boo
9393
func (c *Chroot) Close() error {
9494
PrintVerboseInfo("Chroot.Close", "running...")
9595

96-
err := syscall.Unmount(filepath.Join(c.root, "/dev/pts"), 0)
96+
err := UnmountRecursive(c.root, 0)
9797
if err != nil {
9898
PrintVerboseErr("Chroot.Close", 0, err)
9999
return err
100100
}
101101

102-
mountList := ReservedMounts
103-
if c.etcMounted {
104-
mountList = append(mountList, "/etc")
105-
}
106-
mountList = append(mountList, "")
107-
108-
for _, mount := range mountList {
109-
if mount == "/dev/pts" {
110-
continue
111-
}
112-
113-
mountDir := filepath.Join(c.root, mount)
114-
PrintVerboseInfo("Chroot.Close", "unmounting", mountDir)
115-
err := syscall.Unmount(mountDir, 0)
116-
if err != nil {
117-
PrintVerboseErr("Chroot.Close", 1, err)
118-
return err
119-
}
120-
}
121-
122102
PrintVerboseInfo("Chroot.Close", "successfully closed.")
123103
return nil
124104
}

core/disk-manager.go

Lines changed: 84 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,16 @@ package core
1414
*/
1515

1616
import (
17+
"bufio"
1718
"encoding/json"
18-
"errors"
1919
"fmt"
2020
"os"
2121
"os/exec"
22+
"path/filepath"
2223
"strings"
2324
"syscall"
25+
26+
"golang.org/x/sys/unix"
2427
)
2528

2629
// DiskManager exposes functions to interact with the system's disks
@@ -192,33 +195,97 @@ func (p *Partition) Mount(destination string) error {
192195
return nil
193196
}
194197

195-
// Unmount unmounts a partition
196-
func (p *Partition) Unmount() error {
197-
PrintVerboseInfo("Partition.Unmount", "running...")
198+
// Returns whether the partition is a device-mapper virtual partition
199+
func (p *Partition) IsDevMapper() bool {
200+
return p.Parent != nil
201+
}
202+
203+
// IsEncrypted returns whether the partition is encrypted
204+
func (p *Partition) IsEncrypted() bool {
205+
return strings.HasPrefix(p.FsType, "crypto_")
206+
}
198207

199-
if p.MountPoint == "" {
200-
PrintVerboseErr("Partition.Unmount", 0, errors.New("no mount point"))
201-
return errors.New("no mount point")
208+
func UnmountRecursive(mountPoint string, flags int) error {
209+
mountPointOld := mountPoint
210+
mountPoint, err := filepath.EvalSymlinks(mountPoint)
211+
if err != nil {
212+
return fmt.Errorf("could not find real path for %s: %w", mountPointOld, err)
202213
}
203214

204-
err := syscall.Unmount(p.MountPoint, 0)
215+
systemMountpoints, err := readMountPoints()
205216
if err != nil {
206-
PrintVerboseErr("Partition.Unmount", 1, err)
217+
fmt.Errorf("Could not load system mounts: %w", err)
218+
}
219+
220+
mountId := ""
221+
222+
for id, systemMount := range systemMountpoints {
223+
if systemMount.mountPoint == mountPoint {
224+
mountId = id
225+
}
226+
}
227+
228+
if mountId == "" {
229+
err := unix.Unmount(mountPoint, flags)
207230
return err
208231
}
209232

210-
PrintVerboseInfo("Partition.Unmount", "successfully unmounted", p.MountPoint)
211-
p.MountPoint = ""
233+
err = unmountRecursive(mountId, systemMountpoints, flags, 0)
234+
if err != nil {
235+
return fmt.Errorf("could not recursively unmount %s: %w", mountPoint, err)
236+
}
212237

213238
return nil
214239
}
215240

216-
// Returns whether the partition is a device-mapper virtual partition
217-
func (p *Partition) IsDevMapper() bool {
218-
return p.Parent != nil
241+
func unmountRecursive(mountPointId string, systemMountpoints map[string]mount, flags int, depth int) error {
242+
if depth >= 1000 {
243+
return fmt.Errorf("too many layers when trying to recursively unmount")
244+
}
245+
246+
mount, ok := systemMountpoints[mountPointId]
247+
if !ok {
248+
return fmt.Errorf("could not find mountpoint with id %s", mountPointId)
249+
}
250+
251+
for childMountId, childMount := range systemMountpoints {
252+
if childMount.parentId == mountPointId {
253+
err := unmountRecursive(childMountId, systemMountpoints, flags, depth+1)
254+
if err != nil {
255+
fmt.Errorf("could not unmount %s: %w", childMount.mountPoint)
256+
}
257+
}
258+
}
259+
260+
return unix.Unmount(mount.mountPoint, flags)
219261
}
220262

221-
// IsEncrypted returns whether the partition is encrypted
222-
func (p *Partition) IsEncrypted() bool {
223-
return strings.HasPrefix(p.FsType, "crypto_")
263+
type mount struct {
264+
id string
265+
parentId string
266+
mountPoint string
267+
}
268+
269+
func readMountPoints() (map[string]mount, error) {
270+
f, err := os.Open("/proc/self/mountinfo")
271+
if err != nil {
272+
return nil, err
273+
}
274+
defer f.Close()
275+
276+
mounts := make(map[string]mount)
277+
scanner := bufio.NewScanner(f)
278+
279+
for scanner.Scan() {
280+
fields := strings.Fields(scanner.Text())
281+
if len(fields) < 5 {
282+
continue
283+
}
284+
285+
id := fields[0]
286+
287+
mounts[id] = mount{id: id, parentId: fields[1], mountPoint: fields[4]}
288+
}
289+
290+
return mounts, scanner.Err()
224291
}

core/system.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -272,18 +272,17 @@ func (s *ABSystem) RunOperation(operation ABSystemOperation, deleteBeforeCopy bo
272272
return err
273273
}
274274

275-
partFuture.Partition.Unmount() // just in case
276-
partBoot.Unmount()
277-
278275
futureRoot := "/part-future"
276+
277+
UnmountRecursive(futureRoot, 0)
279278
err = partFuture.Partition.Mount(futureRoot)
280279
if err != nil {
281280
PrintVerboseErr("ABSystem.RunOperation", 2.3, err)
282281
return err
283282
}
284283

285284
cq.Add(func(args ...interface{}) error {
286-
return partFuture.Partition.Unmount()
285+
return UnmountRecursive(futureRoot, 0)
287286
}, nil, 90, &goodies.NoErrorHandler{}, false)
288287

289288
// Stage 3: Make a imageRecipe with user packages
@@ -535,7 +534,7 @@ func (s *ABSystem) RunOperation(operation ABSystemOperation, deleteBeforeCopy bo
535534
}
536535

537536
cq.Add(func(args ...interface{}) error {
538-
return initPartition.Unmount()
537+
return UnmountRecursive(initMountpoint, 0)
539538
}, nil, 80, &goodies.NoErrorHandler{}, false)
540539

541540
futureInitDir := filepath.Join(initMountpoint, partFuture.Label)
@@ -643,7 +642,7 @@ func (s *ABSystem) RunOperation(operation ABSystemOperation, deleteBeforeCopy bo
643642
}
644643

645644
cq.Add(func(args ...interface{}) error {
646-
return partBoot.Unmount()
645+
return UnmountRecursive(tmpBootMount, 0)
647646
}, nil, 100, &goodies.NoErrorHandler{}, false)
648647

649648
// Stage 9: Atomic swap the bootloader
@@ -756,7 +755,7 @@ func (s *ABSystem) Rollback(checkOnly bool) (response ABRollbackResponse, err er
756755
}
757756

758757
cq.Add(func(args ...interface{}) error {
759-
return partBoot.Unmount()
758+
return UnmountRecursive(tmpBootMount, 0)
760759
}, nil, 100, &goodies.NoErrorHandler{}, false)
761760

762761
grub, err := NewGrub(partBoot)

0 commit comments

Comments
 (0)