github.com/alibaba/sealer@v0.8.6-0.20220430115802-37a2bdaa8173/utils/mount/overlay2.go (about) 1 // Copyright © 2021 Alibaba Group Holding Ltd. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //go:build linux 16 // +build linux 17 18 package mount 19 20 import ( 21 "bufio" 22 "fmt" 23 "os" 24 "os/exec" 25 "path" 26 "strings" 27 "syscall" 28 29 "github.com/alibaba/sealer/logger" 30 "github.com/alibaba/sealer/utils" 31 ) 32 33 type Interface interface { 34 // Mount merged layer files 35 Mount(target string, upperDir string, layers ...string) error 36 Unmount(target string) error 37 } 38 39 type Overlay2 struct { 40 } 41 42 func NewMountDriver() Interface { 43 if supportsOverlay() { 44 return &Overlay2{} 45 } 46 return &Default{} 47 } 48 49 func supportsOverlay() bool { 50 if err := exec.Command("modprobe", "overlay").Run(); err != nil { 51 return false 52 } 53 f, err := os.Open("/proc/filesystems") 54 if err != nil { 55 return false 56 } 57 defer func() { 58 if err := f.Close(); err != nil { 59 logger.Fatal("failed to close file") 60 } 61 }() 62 s := bufio.NewScanner(f) 63 for s.Scan() { 64 if s.Text() == "nodev\toverlay" { 65 return true 66 } 67 } 68 return false 69 } 70 71 // Mount using overlay2 to merged layer files 72 func (o *Overlay2) Mount(target string, upperLayer string, layers ...string) error { 73 if target == "" { 74 return fmt.Errorf("target cannot be empty") 75 } 76 if len(layers) == 0 { 77 return fmt.Errorf("layers cannot be empty") 78 } 79 workdir := path.Join(target, "work") 80 if err := utils.Mkdir(workdir); err != nil { 81 return fmt.Errorf("create workdir failed") 82 } 83 var err error 84 defer func() { 85 if err != nil { 86 _ = os.RemoveAll(workdir) 87 } 88 }() 89 90 var indexOff string 91 // figure out whether "index=off" option is recognized by the kernel 92 _, err = os.Stat("/sys/module/overlay/parameters/index") 93 switch { 94 case err == nil: 95 indexOff = "index=off," 96 case os.IsNotExist(err): 97 // old kernel, no index -- do nothing 98 default: 99 logger.Warn("Unable to detect whether overlay kernel module supports index parameter: %s", err) 100 } 101 102 mountData := fmt.Sprintf("%slowerdir=%s,upperdir=%s,workdir=%s", indexOff, strings.Join(utils.Reverse(layers), ":"), upperLayer, workdir) 103 logger.Debug("mount data : %s", mountData) 104 if err = mount("overlay", target, "overlay", 0, mountData); err != nil { 105 return fmt.Errorf("error creating overlay mount to %s: %v", target, err) 106 } 107 return nil 108 } 109 110 // Unmount target 111 func (o *Overlay2) Unmount(target string) error { 112 return unmount(target, syscall.MNT_DETACH) 113 } 114 115 func mount(device, target, mType string, flag uintptr, data string) error { 116 if err := syscall.Mount(device, target, mType, flag, data); err != nil { 117 return err 118 } 119 120 // If we have a bind mount or remount, remount... 121 if flag&syscall.MS_BIND == syscall.MS_BIND && flag&syscall.MS_RDONLY == syscall.MS_RDONLY { 122 return syscall.Mount(device, target, mType, flag|syscall.MS_REMOUNT, data) 123 } 124 return nil 125 } 126 127 func unmount(target string, flag int) error { 128 return syscall.Unmount(target, flag) 129 }