@@ -19,6 +19,7 @@ package mount
1919import (
2020 "fmt"
2121 "os"
22+ "os/exec"
2223 "path"
2324 "strings"
2425 "time"
@@ -28,14 +29,27 @@ import (
2829 "golang.org/x/sys/unix"
2930)
3031
31- var pagesize = 4096
32+ var (
33+ pagesize = 4096
34+ allowedHelperBinaries = []string {"mount.fuse" , "mount.fuse3" }
35+ )
3236
3337func init () {
3438 pagesize = os .Getpagesize ()
3539}
3640
37- // Mount to the provided target path
41+ // Mount to the provided target path.
42+ //
43+ // If m.Type starts with "fuse." or "fuse3.", "mount.fuse" or "mount.fuse3"
44+ // helper binary is called.
3845func (m * Mount ) Mount (target string ) error {
46+ for _ , helperBinary := range allowedHelperBinaries {
47+ // helperBinary = "mount.fuse", typePrefix = "fuse."
48+ typePrefix := strings .TrimPrefix (helperBinary , "mount." ) + "."
49+ if strings .HasPrefix (m .Type , typePrefix ) {
50+ return m .mountWithHelper (helperBinary , typePrefix , target )
51+ }
52+ }
3953 var (
4054 chdir string
4155 options = m .Options
@@ -92,7 +106,28 @@ func Unmount(target string, flags int) error {
92106 return nil
93107}
94108
109+ func isFUSE (dir string ) (bool , error ) {
110+ // fuseSuperMagic is defined in statfs(2)
111+ const fuseSuperMagic = 0x65735546
112+ var st unix.Statfs_t
113+ if err := unix .Statfs (dir , & st ); err != nil {
114+ return false , err
115+ }
116+ return st .Type == fuseSuperMagic , nil
117+ }
118+
95119func unmount (target string , flags int ) error {
120+ // For FUSE mounts, attempting to execute fusermount helper binary is preferred
121+ // https://github.com/containerd/containerd/pull/3765#discussion_r342083514
122+ if ok , err := isFUSE (target ); err == nil && ok {
123+ for _ , helperBinary := range []string {"fusermount3" , "fusermount" } {
124+ cmd := exec .Command (helperBinary , "-u" , target )
125+ if err := cmd .Run (); err == nil {
126+ return nil
127+ }
128+ // ignore error and try unix.Unmount
129+ }
130+ }
96131 for i := 0 ; i < 50 ; i ++ {
97132 if err := unix .Unmount (target , flags ); err != nil {
98133 switch err {
@@ -317,3 +352,21 @@ func mountAt(chdir string, source, target, fstype string, flags uintptr, data st
317352 }
318353 return errors .Wrap (sys .FMountat (f .Fd (), source , target , fstype , flags , data ), "failed to mountat" )
319354}
355+
356+ func (m * Mount ) mountWithHelper (helperBinary , typePrefix , target string ) error {
357+ // helperBinary: "mount.fuse3"
358+ // target: "/foo/merged"
359+ // m.Type: "fuse3.fuse-overlayfs"
360+ // command: "mount.fuse3 overlay /foo/merged -o lowerdir=/foo/lower2:/foo/lower1,upperdir=/foo/upper,workdir=/foo/work -t fuse-overlayfs"
361+ args := []string {m .Source , target }
362+ for _ , o := range m .Options {
363+ args = append (args , "-o" , o )
364+ }
365+ args = append (args , "-t" , strings .TrimPrefix (m .Type , typePrefix ))
366+ cmd := exec .Command (helperBinary , args ... )
367+ out , err := cmd .CombinedOutput ()
368+ if err != nil {
369+ return errors .Wrapf (err , "mount helper [%s %v] failed: %q" , helperBinary , args , string (out ))
370+ }
371+ return nil
372+ }
0 commit comments