github.com/lazyboychen7/engine@v17.12.1-ce-rc2+incompatible/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/docker/docker/pkg/system" 14 "github.com/pkg/errors" 15 "github.com/sirupsen/logrus" 16 "golang.org/x/sys/unix" 17 ) 18 19 // doesSupportNativeDiff checks whether the filesystem has a bug 20 // which copies up the opaque flag when copying up an opaque 21 // directory or the kernel enable CONFIG_OVERLAY_FS_REDIRECT_DIR. 22 // When these exist naive diff should be used. 23 func doesSupportNativeDiff(d string) error { 24 td, err := ioutil.TempDir(d, "opaque-bug-check") 25 if err != nil { 26 return err 27 } 28 defer func() { 29 if err := os.RemoveAll(td); err != nil { 30 logrus.Warnf("Failed to remove check directory %v: %v", td, err) 31 } 32 }() 33 34 // Make directories l1/d, l1/d1, l2/d, l3, work, merged 35 if err := os.MkdirAll(filepath.Join(td, "l1", "d"), 0755); err != nil { 36 return err 37 } 38 if err := os.MkdirAll(filepath.Join(td, "l1", "d1"), 0755); err != nil { 39 return err 40 } 41 if err := os.MkdirAll(filepath.Join(td, "l2", "d"), 0755); err != nil { 42 return err 43 } 44 if err := os.Mkdir(filepath.Join(td, "l3"), 0755); err != nil { 45 return err 46 } 47 if err := os.Mkdir(filepath.Join(td, "work"), 0755); err != nil { 48 return err 49 } 50 if err := os.Mkdir(filepath.Join(td, "merged"), 0755); err != nil { 51 return err 52 } 53 54 // Mark l2/d as opaque 55 if err := system.Lsetxattr(filepath.Join(td, "l2", "d"), "trusted.overlay.opaque", []byte("y"), 0); err != nil { 56 return errors.Wrap(err, "failed to set opaque flag on middle layer") 57 } 58 59 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")) 60 if err := unix.Mount("overlay", filepath.Join(td, "merged"), "overlay", 0, opts); err != nil { 61 return errors.Wrap(err, "failed to mount overlay") 62 } 63 defer func() { 64 if err := unix.Unmount(filepath.Join(td, "merged"), 0); err != nil { 65 logrus.Warnf("Failed to unmount check directory %v: %v", filepath.Join(td, "merged"), err) 66 } 67 }() 68 69 // Touch file in d to force copy up of opaque directory "d" from "l2" to "l3" 70 if err := ioutil.WriteFile(filepath.Join(td, "merged", "d", "f"), []byte{}, 0644); err != nil { 71 return errors.Wrap(err, "failed to write to merged directory") 72 } 73 74 // Check l3/d does not have opaque flag 75 xattrOpaque, err := system.Lgetxattr(filepath.Join(td, "l3", "d"), "trusted.overlay.opaque") 76 if err != nil { 77 return errors.Wrap(err, "failed to read opaque flag on upper layer") 78 } 79 if string(xattrOpaque) == "y" { 80 return errors.New("opaque flag erroneously copied up, consider update to kernel 4.8 or later to fix") 81 } 82 83 // rename "d1" to "d2" 84 if err := os.Rename(filepath.Join(td, "merged", "d1"), filepath.Join(td, "merged", "d2")); err != nil { 85 // if rename failed with syscall.EXDEV, the kernel doesn't have CONFIG_OVERLAY_FS_REDIRECT_DIR enabled 86 if err.(*os.LinkError).Err == syscall.EXDEV { 87 return nil 88 } 89 return errors.Wrap(err, "failed to rename dir in merged directory") 90 } 91 // get the xattr of "d2" 92 xattrRedirect, err := system.Lgetxattr(filepath.Join(td, "l3", "d2"), "trusted.overlay.redirect") 93 if err != nil { 94 return errors.Wrap(err, "failed to read redirect flag on upper layer") 95 } 96 97 if string(xattrRedirect) == "d1" { 98 return errors.New("kernel has CONFIG_OVERLAY_FS_REDIRECT_DIR enabled") 99 } 100 101 return nil 102 } 103 104 // supportsMultipleLowerDir checks if the system supports multiple lowerdirs, 105 // which is required for the overlay2 driver. On 4.x kernels, multiple lowerdirs 106 // are always available (so this check isn't needed), and backported to RHEL and 107 // CentOS 3.x kernels (3.10.0-693.el7.x86_64 and up). This function is to detect 108 // support on those kernels, without doing a kernel version compare. 109 func supportsMultipleLowerDir(d string) error { 110 td, err := ioutil.TempDir(d, "multiple-lowerdir-check") 111 if err != nil { 112 return err 113 } 114 defer func() { 115 if err := os.RemoveAll(td); err != nil { 116 logrus.Warnf("Failed to remove check directory %v: %v", td, err) 117 } 118 }() 119 120 for _, dir := range []string{"lower1", "lower2", "upper", "work", "merged"} { 121 if err := os.Mkdir(filepath.Join(td, dir), 0755); err != nil { 122 return err 123 } 124 } 125 126 opts := fmt.Sprintf("lowerdir=%s:%s,upperdir=%s,workdir=%s", path.Join(td, "lower2"), path.Join(td, "lower1"), path.Join(td, "upper"), path.Join(td, "work")) 127 if err := unix.Mount("overlay", filepath.Join(td, "merged"), "overlay", 0, opts); err != nil { 128 return errors.Wrap(err, "failed to mount overlay") 129 } 130 if err := unix.Unmount(filepath.Join(td, "merged"), 0); err != nil { 131 logrus.Warnf("Failed to unmount check directory %v: %v", filepath.Join(td, "merged"), err) 132 } 133 return nil 134 }