gopkg.in/dotcloud/docker.v1@v1.13.1/daemon/graphdriver/overlay2/check.go (about)

     1  // +build linux
     2  
     3  package overlay2
     4  
     5  import (
     6  	"fmt"
     7  	"io/ioutil"
     8  	"os"
     9  	"path"
    10  	"path/filepath"
    11  	"syscall"
    12  
    13  	"github.com/Sirupsen/logrus"
    14  	"github.com/docker/docker/pkg/system"
    15  	"github.com/pkg/errors"
    16  )
    17  
    18  // hasOpaqueCopyUpBug checks whether the filesystem has a bug
    19  // which copies up the opaque flag when copying up an opaque
    20  // directory. When this bug exists naive diff should be used.
    21  func hasOpaqueCopyUpBug(d string) error {
    22  	td, err := ioutil.TempDir(d, "opaque-bug-check")
    23  	if err != nil {
    24  		return err
    25  	}
    26  	defer func() {
    27  		if err := os.RemoveAll(td); err != nil {
    28  			logrus.Warnf("Failed to remove check directory %v: %v", td, err)
    29  		}
    30  	}()
    31  
    32  	// Make directories l1/d, l2/d, l3, work, merged
    33  	if err := os.MkdirAll(filepath.Join(td, "l1", "d"), 0755); err != nil {
    34  		return err
    35  	}
    36  	if err := os.MkdirAll(filepath.Join(td, "l2", "d"), 0755); err != nil {
    37  		return err
    38  	}
    39  	if err := os.Mkdir(filepath.Join(td, "l3"), 0755); err != nil {
    40  		return err
    41  	}
    42  	if err := os.Mkdir(filepath.Join(td, "work"), 0755); err != nil {
    43  		return err
    44  	}
    45  	if err := os.Mkdir(filepath.Join(td, "merged"), 0755); err != nil {
    46  		return err
    47  	}
    48  
    49  	// Mark l2/d as opaque
    50  	if err := system.Lsetxattr(filepath.Join(td, "l2", "d"), "trusted.overlay.opaque", []byte("y"), 0); err != nil {
    51  		return errors.Wrap(err, "failed to set opaque flag on middle layer")
    52  	}
    53  
    54  	opts := fmt.Sprintf("lowerdir=%s:%s,upperdir=%s,workdir=%s", path.Join(td, "l2"), path.Join(td, "l1"), path.Join(td, "l3"), path.Join(td, "work"))
    55  	if err := syscall.Mount("overlay", filepath.Join(td, "merged"), "overlay", 0, opts); err != nil {
    56  		return errors.Wrap(err, "failed to mount overlay")
    57  	}
    58  	defer func() {
    59  		if err := syscall.Unmount(filepath.Join(td, "merged"), 0); err != nil {
    60  			logrus.Warnf("Failed to unmount check directory %v: %v", filepath.Join(td, "merged"), err)
    61  		}
    62  	}()
    63  
    64  	// Touch file in d to force copy up of opaque directory "d" from "l2" to "l3"
    65  	if err := ioutil.WriteFile(filepath.Join(td, "merged", "d", "f"), []byte{}, 0644); err != nil {
    66  		return errors.Wrap(err, "failed to write to merged directory")
    67  	}
    68  
    69  	// Check l3/d does not have opaque flag
    70  	xattrOpaque, err := system.Lgetxattr(filepath.Join(td, "l3", "d"), "trusted.overlay.opaque")
    71  	if err != nil {
    72  		return errors.Wrap(err, "failed to read opaque flag on upper layer")
    73  	}
    74  	if string(xattrOpaque) == "y" {
    75  		return errors.New("opaque flag erroneously copied up, consider update to kernel 4.8 or later to fix")
    76  	}
    77  
    78  	return nil
    79  }