github.com/mforkel/docker-ce-i386@v17.12.1-ce-rc2+incompatible/components/engine/daemon/daemon_linux.go (about) 1 package daemon 2 3 import ( 4 "bufio" 5 "fmt" 6 "io" 7 "os" 8 "regexp" 9 "strings" 10 11 "github.com/docker/docker/pkg/fileutils" 12 "github.com/docker/docker/pkg/mount" 13 "github.com/pkg/errors" 14 "github.com/sirupsen/logrus" 15 ) 16 17 // On Linux, plugins use a static path for storing execution state, 18 // instead of deriving path from daemon's exec-root. This is because 19 // plugin socket files are created here and they cannot exceed max 20 // path length of 108 bytes. 21 func getPluginExecRoot(root string) string { 22 return "/run/docker/plugins" 23 } 24 25 func (daemon *Daemon) cleanupMountsByID(id string) error { 26 logrus.Debugf("Cleaning up old mountid %s: start.", id) 27 f, err := os.Open("/proc/self/mountinfo") 28 if err != nil { 29 return err 30 } 31 defer f.Close() 32 33 return daemon.cleanupMountsFromReaderByID(f, id, mount.Unmount) 34 } 35 36 func (daemon *Daemon) cleanupMountsFromReaderByID(reader io.Reader, id string, unmount func(target string) error) error { 37 if daemon.root == "" { 38 return nil 39 } 40 var errors []string 41 42 regexps := getCleanPatterns(id) 43 sc := bufio.NewScanner(reader) 44 for sc.Scan() { 45 if fields := strings.Fields(sc.Text()); len(fields) >= 4 { 46 if mnt := fields[4]; strings.HasPrefix(mnt, daemon.root) { 47 for _, p := range regexps { 48 if p.MatchString(mnt) { 49 if err := unmount(mnt); err != nil { 50 logrus.Error(err) 51 errors = append(errors, err.Error()) 52 } 53 } 54 } 55 } 56 } 57 } 58 59 if err := sc.Err(); err != nil { 60 return err 61 } 62 63 if len(errors) > 0 { 64 return fmt.Errorf("Error cleaning up mounts:\n%v", strings.Join(errors, "\n")) 65 } 66 67 logrus.Debugf("Cleaning up old mountid %v: done.", id) 68 return nil 69 } 70 71 // cleanupMounts umounts used by container resources and the daemon root mount 72 func (daemon *Daemon) cleanupMounts() error { 73 if err := daemon.cleanupMountsByID(""); err != nil { 74 return err 75 } 76 77 infos, err := mount.GetMounts() 78 if err != nil { 79 return errors.Wrap(err, "error reading mount table for cleanup") 80 } 81 82 info := getMountInfo(infos, daemon.root) 83 // `info.Root` here is the root mountpoint of the passed in path (`daemon.root`). 84 // The ony cases that need to be cleaned up is when the daemon has performed a 85 // `mount --bind /daemon/root /daemon/root && mount --make-shared /daemon/root` 86 // This is only done when the daemon is started up and `/daemon/root` is not 87 // already on a shared mountpoint. 88 if !shouldUnmountRoot(daemon.root, info) { 89 return nil 90 } 91 92 logrus.WithField("mountpoint", daemon.root).Debug("unmounting daemon root") 93 return mount.Unmount(daemon.root) 94 } 95 96 func getCleanPatterns(id string) (regexps []*regexp.Regexp) { 97 var patterns []string 98 if id == "" { 99 id = "[0-9a-f]{64}" 100 patterns = append(patterns, "containers/"+id+"/shm") 101 } 102 patterns = append(patterns, "aufs/mnt/"+id+"$", "overlay/"+id+"/merged$", "zfs/graph/"+id+"$") 103 for _, p := range patterns { 104 r, err := regexp.Compile(p) 105 if err == nil { 106 regexps = append(regexps, r) 107 } 108 } 109 return 110 } 111 112 func getRealPath(path string) (string, error) { 113 return fileutils.ReadSymlinkedDirectory(path) 114 } 115 116 func shouldUnmountRoot(root string, info *mount.Info) bool { 117 if info == nil { 118 return false 119 } 120 if info.Mountpoint != root { 121 return false 122 } 123 if !strings.HasSuffix(root, info.Root) { 124 return false 125 } 126 return hasMountinfoOption(info.Optional, sharedPropagationOption) 127 }