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  }