| ... | ... |
@@ -74,18 +74,22 @@ func (daemon *Daemon) cleanupMounts() error {
|
| 74 | 74 |
return err |
| 75 | 75 |
} |
| 76 | 76 |
|
| 77 |
- infos, err := mount.GetMounts() |
|
| 77 |
+ info, err := mount.GetMounts(mount.SingleEntryFilter(daemon.root)) |
|
| 78 | 78 |
if err != nil {
|
| 79 | 79 |
return errors.Wrap(err, "error reading mount table for cleanup") |
| 80 | 80 |
} |
| 81 | 81 |
|
| 82 |
- info := getMountInfo(infos, daemon.root) |
|
| 82 |
+ if len(info) < 1 {
|
|
| 83 |
+ // no mount found, we're done here |
|
| 84 |
+ return nil |
|
| 85 |
+ } |
|
| 86 |
+ |
|
| 83 | 87 |
// `info.Root` here is the root mountpoint of the passed in path (`daemon.root`). |
| 84 | 88 |
// The ony cases that need to be cleaned up is when the daemon has performed a |
| 85 | 89 |
// `mount --bind /daemon/root /daemon/root && mount --make-shared /daemon/root` |
| 86 | 90 |
// This is only done when the daemon is started up and `/daemon/root` is not |
| 87 | 91 |
// already on a shared mountpoint. |
| 88 |
- if !shouldUnmountRoot(daemon.root, info) {
|
|
| 92 |
+ if !shouldUnmountRoot(daemon.root, info[0]) {
|
|
| 89 | 93 |
return nil |
| 90 | 94 |
} |
| 91 | 95 |
|
| ... | ... |
@@ -122,12 +126,6 @@ func getRealPath(path string) (string, error) {
|
| 122 | 122 |
} |
| 123 | 123 |
|
| 124 | 124 |
func shouldUnmountRoot(root string, info *mount.Info) bool {
|
| 125 |
- if info == nil {
|
|
| 126 |
- return false |
|
| 127 |
- } |
|
| 128 |
- if info.Mountpoint != root {
|
|
| 129 |
- return false |
|
| 130 |
- } |
|
| 131 | 125 |
if !strings.HasSuffix(root, info.Root) {
|
| 132 | 126 |
return false |
| 133 | 127 |
} |
| ... | ... |
@@ -184,12 +184,6 @@ func TestShouldUnmountRoot(t *testing.T) {
|
| 184 | 184 |
expect: true, |
| 185 | 185 |
}, |
| 186 | 186 |
{
|
| 187 |
- desc: "not a mountpoint", |
|
| 188 |
- root: "/docker", |
|
| 189 |
- info: nil, |
|
| 190 |
- expect: false, |
|
| 191 |
- }, |
|
| 192 |
- {
|
|
| 193 | 187 |
desc: "root is at in a submount from `/`", |
| 194 | 188 |
root: "/foo/docker", |
| 195 | 189 |
info: &mount.Info{Root: "/docker", Mountpoint: "/foo/docker"},
|
| ... | ... |
@@ -201,12 +195,6 @@ func TestShouldUnmountRoot(t *testing.T) {
|
| 201 | 201 |
info: &mount.Info{Root: "/docker/volumes/1234657/_data", Mountpoint: "/docker"},
|
| 202 | 202 |
expect: false, |
| 203 | 203 |
}, |
| 204 |
- {
|
|
| 205 |
- desc: "root is mounted in from a parent mount namespace different root dir", |
|
| 206 |
- root: "/foo/bar", |
|
| 207 |
- info: &mount.Info{Root: "/docker/volumes/1234657/_data", Mountpoint: "/foo/bar"},
|
|
| 208 |
- expect: false, |
|
| 209 |
- }, |
|
| 210 | 204 |
} {
|
| 211 | 205 |
t.Run(test.desc, func(t *testing.T) {
|
| 212 | 206 |
for _, options := range []struct {
|
| ... | ... |
@@ -380,15 +380,6 @@ func specMapping(s []idtools.IDMap) []specs.LinuxIDMapping {
|
| 380 | 380 |
return ids |
| 381 | 381 |
} |
| 382 | 382 |
|
| 383 |
-func getMountInfo(mountinfo []*mount.Info, dir string) *mount.Info {
|
|
| 384 |
- for _, m := range mountinfo {
|
|
| 385 |
- if m.Mountpoint == dir {
|
|
| 386 |
- return m |
|
| 387 |
- } |
|
| 388 |
- } |
|
| 389 |
- return nil |
|
| 390 |
-} |
|
| 391 |
- |
|
| 392 | 383 |
// Get the source mount point of directory passed in as argument. Also return |
| 393 | 384 |
// optional fields. |
| 394 | 385 |
func getSourceMount(source string) (string, string, error) {
|
| ... | ... |
@@ -398,29 +389,26 @@ func getSourceMount(source string) (string, string, error) {
|
| 398 | 398 |
return "", "", err |
| 399 | 399 |
} |
| 400 | 400 |
|
| 401 |
- mountinfos, err := mount.GetMounts() |
|
| 401 |
+ mi, err := mount.GetMounts(mount.ParentsFilter(sourcePath)) |
|
| 402 | 402 |
if err != nil {
|
| 403 | 403 |
return "", "", err |
| 404 | 404 |
} |
| 405 |
- |
|
| 406 |
- mountinfo := getMountInfo(mountinfos, sourcePath) |
|
| 407 |
- if mountinfo != nil {
|
|
| 408 |
- return sourcePath, mountinfo.Optional, nil |
|
| 405 |
+ if len(mi) < 1 {
|
|
| 406 |
+ return "", "", fmt.Errorf("Can't find mount point of %s", source)
|
|
| 409 | 407 |
} |
| 410 | 408 |
|
| 411 |
- path := sourcePath |
|
| 412 |
- for {
|
|
| 413 |
- path = filepath.Dir(path) |
|
| 414 |
- |
|
| 415 |
- mountinfo = getMountInfo(mountinfos, path) |
|
| 416 |
- if mountinfo != nil {
|
|
| 417 |
- return path, mountinfo.Optional, nil |
|
| 418 |
- } |
|
| 419 |
- |
|
| 420 |
- if path == "/" {
|
|
| 421 |
- break |
|
| 409 |
+ // find the longest mount point |
|
| 410 |
+ var idx, maxlen int |
|
| 411 |
+ for i := range mi {
|
|
| 412 |
+ if len(mi[i].Mountpoint) > maxlen {
|
|
| 413 |
+ maxlen = len(mi[i].Mountpoint) |
|
| 414 |
+ idx = i |
|
| 422 | 415 |
} |
| 423 | 416 |
} |
| 417 |
+ // and return it unless it's "/" |
|
| 418 |
+ if mi[idx].Mountpoint != "/" {
|
|
| 419 |
+ return mi[idx].Mountpoint, mi[idx].Optional, nil |
|
| 420 |
+ } |
|
| 424 | 421 |
|
| 425 | 422 |
// If we are here, we did not find parent mount. Something is wrong. |
| 426 | 423 |
return "", "", fmt.Errorf("Could not find source mount of %s", source)
|
| ... | ... |
@@ -260,7 +260,7 @@ func (s *DockerDaemonSuite) TestPluginVolumeRemoveOnRestart(c *check.C) {
|
| 260 | 260 |
} |
| 261 | 261 |
|
| 262 | 262 |
func existsMountpointWithPrefix(mountpointPrefix string) (bool, error) {
|
| 263 |
- mounts, err := mount.GetMounts() |
|
| 263 |
+ mounts, err := mount.GetMounts(nil) |
|
| 264 | 264 |
if err != nil {
|
| 265 | 265 |
return false, err |
| 266 | 266 |
} |
| ... | ... |
@@ -3,32 +3,64 @@ package mount // import "github.com/docker/docker/pkg/mount" |
| 3 | 3 |
import ( |
| 4 | 4 |
"sort" |
| 5 | 5 |
"strings" |
| 6 |
- |
|
| 7 | 6 |
"syscall" |
| 8 | 7 |
|
| 9 | 8 |
"github.com/sirupsen/logrus" |
| 10 | 9 |
) |
| 11 | 10 |
|
| 12 |
-// GetMounts retrieves a list of mounts for the current running process. |
|
| 13 |
-func GetMounts() ([]*Info, error) {
|
|
| 14 |
- return parseMountTable() |
|
| 11 |
+// FilterFunc is a type defining a callback function |
|
| 12 |
+// to filter out unwanted entries. It takes a pointer |
|
| 13 |
+// to an Info struct (not fully populated, currently |
|
| 14 |
+// only Mountpoint is filled in), and returns two booleans: |
|
| 15 |
+// - skip: true if the entry should be skipped |
|
| 16 |
+// - stop: true if parsing should be stopped after the entry |
|
| 17 |
+type FilterFunc func(*Info) (skip, stop bool) |
|
| 18 |
+ |
|
| 19 |
+// PrefixFilter discards all entries whose mount points |
|
| 20 |
+// do not start with a prefix specified |
|
| 21 |
+func PrefixFilter(prefix string) FilterFunc {
|
|
| 22 |
+ return func(m *Info) (bool, bool) {
|
|
| 23 |
+ skip := !strings.HasPrefix(m.Mountpoint, prefix) |
|
| 24 |
+ return skip, false |
|
| 25 |
+ } |
|
| 26 |
+} |
|
| 27 |
+ |
|
| 28 |
+// SingleEntryFilter looks for a specific entry |
|
| 29 |
+func SingleEntryFilter(mp string) FilterFunc {
|
|
| 30 |
+ return func(m *Info) (bool, bool) {
|
|
| 31 |
+ if m.Mountpoint == mp {
|
|
| 32 |
+ return false, true // don't skip, stop now |
|
| 33 |
+ } |
|
| 34 |
+ return true, false // skip, keep going |
|
| 35 |
+ } |
|
| 36 |
+} |
|
| 37 |
+ |
|
| 38 |
+// ParentsFilter returns all entries whose mount points |
|
| 39 |
+// can be parents of a path specified, discarding others. |
|
| 40 |
+// For example, given `/var/lib/docker/something`, entries |
|
| 41 |
+// like `/var/lib/docker`, `/var` and `/` are returned. |
|
| 42 |
+func ParentsFilter(path string) FilterFunc {
|
|
| 43 |
+ return func(m *Info) (bool, bool) {
|
|
| 44 |
+ skip := !strings.HasPrefix(path, m.Mountpoint) |
|
| 45 |
+ return skip, false |
|
| 46 |
+ } |
|
| 47 |
+} |
|
| 48 |
+ |
|
| 49 |
+// GetMounts retrieves a list of mounts for the current running process, |
|
| 50 |
+// with an optional filter applied (use nil for no filter). |
|
| 51 |
+func GetMounts(f FilterFunc) ([]*Info, error) {
|
|
| 52 |
+ return parseMountTable(f) |
|
| 15 | 53 |
} |
| 16 | 54 |
|
| 17 | 55 |
// Mounted determines if a specified mountpoint has been mounted. |
| 18 | 56 |
// On Linux it looks at /proc/self/mountinfo. |
| 19 | 57 |
func Mounted(mountpoint string) (bool, error) {
|
| 20 |
- entries, err := parseMountTable() |
|
| 58 |
+ entries, err := GetMounts(SingleEntryFilter(mountpoint)) |
|
| 21 | 59 |
if err != nil {
|
| 22 | 60 |
return false, err |
| 23 | 61 |
} |
| 24 | 62 |
|
| 25 |
- // Search the table for the mountpoint |
|
| 26 |
- for _, e := range entries {
|
|
| 27 |
- if e.Mountpoint == mountpoint {
|
|
| 28 |
- return true, nil |
|
| 29 |
- } |
|
| 30 |
- } |
|
| 31 |
- return false, nil |
|
| 63 |
+ return len(entries) > 0, nil |
|
| 32 | 64 |
} |
| 33 | 65 |
|
| 34 | 66 |
// Mount will mount filesystem according to the specified configuration, on the |
| ... | ... |
@@ -57,16 +89,18 @@ func ForceMount(device, target, mType, options string) error {
|
| 57 | 57 |
// Unmount lazily unmounts a filesystem on supported platforms, otherwise |
| 58 | 58 |
// does a normal unmount. |
| 59 | 59 |
func Unmount(target string) error {
|
| 60 |
- if mounted, err := Mounted(target); err != nil || !mounted {
|
|
| 61 |
- return err |
|
| 60 |
+ err := unmount(target, mntDetach) |
|
| 61 |
+ if err == syscall.EINVAL {
|
|
| 62 |
+ // ignore "not mounted" error |
|
| 63 |
+ err = nil |
|
| 62 | 64 |
} |
| 63 |
- return unmount(target, mntDetach) |
|
| 65 |
+ return err |
|
| 64 | 66 |
} |
| 65 | 67 |
|
| 66 | 68 |
// RecursiveUnmount unmounts the target and all mounts underneath, starting with |
| 67 | 69 |
// the deepsest mount first. |
| 68 | 70 |
func RecursiveUnmount(target string) error {
|
| 69 |
- mounts, err := GetMounts() |
|
| 71 |
+ mounts, err := parseMountTable(PrefixFilter(target)) |
|
| 70 | 72 |
if err != nil {
|
| 71 | 73 |
return err |
| 72 | 74 |
} |
| ... | ... |
@@ -77,9 +111,6 @@ func RecursiveUnmount(target string) error {
|
| 77 | 77 |
}) |
| 78 | 78 |
|
| 79 | 79 |
for i, m := range mounts {
|
| 80 |
- if !strings.HasPrefix(m.Mountpoint, target) {
|
|
| 81 |
- continue |
|
| 82 |
- } |
|
| 83 | 80 |
logrus.Debugf("Trying to unmount %s", m.Mountpoint)
|
| 84 | 81 |
err = unmount(m.Mountpoint, mntDetach) |
| 85 | 82 |
if err != nil {
|
| ... | ... |
@@ -121,7 +121,7 @@ func ensureUnmount(t *testing.T, mnt string) {
|
| 121 | 121 |
|
| 122 | 122 |
// validateMount checks that mnt has the given options |
| 123 | 123 |
func validateMount(t *testing.T, mnt string, opts, optional, vfs string) {
|
| 124 |
- info, err := GetMounts() |
|
| 124 |
+ info, err := GetMounts(nil) |
|
| 125 | 125 |
if err != nil {
|
| 126 | 126 |
t.Fatal(err) |
| 127 | 127 |
} |
| ... | ... |
@@ -15,7 +15,7 @@ import ( |
| 15 | 15 |
|
| 16 | 16 |
// Parse /proc/self/mountinfo because comparing Dev and ino does not work from |
| 17 | 17 |
// bind mounts. |
| 18 |
-func parseMountTable() ([]*Info, error) {
|
|
| 18 |
+func parseMountTable(filter FilterFunc) ([]*Info, error) {
|
|
| 19 | 19 |
var rawEntries *C.struct_statfs |
| 20 | 20 |
|
| 21 | 21 |
count := int(C.getmntinfo(&rawEntries, C.MNT_WAIT)) |
| ... | ... |
@@ -32,10 +32,24 @@ func parseMountTable() ([]*Info, error) {
|
| 32 | 32 |
var out []*Info |
| 33 | 33 |
for _, entry := range entries {
|
| 34 | 34 |
var mountinfo Info |
| 35 |
+ var skip, stop bool |
|
| 35 | 36 |
mountinfo.Mountpoint = C.GoString(&entry.f_mntonname[0]) |
| 37 |
+ |
|
| 38 |
+ if filter != nil {
|
|
| 39 |
+ // filter out entries we're not interested in |
|
| 40 |
+ skip, stop = filter(p) |
|
| 41 |
+ if skip {
|
|
| 42 |
+ continue |
|
| 43 |
+ } |
|
| 44 |
+ } |
|
| 45 |
+ |
|
| 36 | 46 |
mountinfo.Source = C.GoString(&entry.f_mntfromname[0]) |
| 37 | 47 |
mountinfo.Fstype = C.GoString(&entry.f_fstypename[0]) |
| 48 |
+ |
|
| 38 | 49 |
out = append(out, &mountinfo) |
| 50 |
+ if stop {
|
|
| 51 |
+ break |
|
| 52 |
+ } |
|
| 39 | 53 |
} |
| 40 | 54 |
return out, nil |
| 41 | 55 |
} |
| ... | ... |
@@ -5,80 +5,119 @@ import ( |
| 5 | 5 |
"fmt" |
| 6 | 6 |
"io" |
| 7 | 7 |
"os" |
| 8 |
+ "strconv" |
|
| 8 | 9 |
"strings" |
| 9 | 10 |
) |
| 10 | 11 |
|
| 11 |
-const ( |
|
| 12 |
- /* 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue |
|
| 13 |
- (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11) |
|
| 12 |
+func parseInfoFile(r io.Reader, filter FilterFunc) ([]*Info, error) {
|
|
| 13 |
+ s := bufio.NewScanner(r) |
|
| 14 |
+ out := []*Info{}
|
|
| 15 |
+ for s.Scan() {
|
|
| 16 |
+ if err := s.Err(); err != nil {
|
|
| 17 |
+ return nil, err |
|
| 18 |
+ } |
|
| 19 |
+ /* |
|
| 20 |
+ 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue |
|
| 21 |
+ (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11) |
|
| 14 | 22 |
|
| 15 |
- (1) mount ID: unique identifier of the mount (may be reused after umount) |
|
| 16 |
- (2) parent ID: ID of parent (or of self for the top of the mount tree) |
|
| 17 |
- (3) major:minor: value of st_dev for files on filesystem |
|
| 18 |
- (4) root: root of the mount within the filesystem |
|
| 19 |
- (5) mount point: mount point relative to the process's root |
|
| 20 |
- (6) mount options: per mount options |
|
| 21 |
- (7) optional fields: zero or more fields of the form "tag[:value]" |
|
| 22 |
- (8) separator: marks the end of the optional fields |
|
| 23 |
- (9) filesystem type: name of filesystem of the form "type[.subtype]" |
|
| 24 |
- (10) mount source: filesystem specific information or "none" |
|
| 25 |
- (11) super options: per super block options*/ |
|
| 26 |
- mountinfoFormat = "%d %d %d:%d %s %s %s %s" |
|
| 27 |
-) |
|
| 23 |
+ (1) mount ID: unique identifier of the mount (may be reused after umount) |
|
| 24 |
+ (2) parent ID: ID of parent (or of self for the top of the mount tree) |
|
| 25 |
+ (3) major:minor: value of st_dev for files on filesystem |
|
| 26 |
+ (4) root: root of the mount within the filesystem |
|
| 27 |
+ (5) mount point: mount point relative to the process's root |
|
| 28 |
+ (6) mount options: per mount options |
|
| 29 |
+ (7) optional fields: zero or more fields of the form "tag[:value]" |
|
| 30 |
+ (8) separator: marks the end of the optional fields |
|
| 31 |
+ (9) filesystem type: name of filesystem of the form "type[.subtype]" |
|
| 32 |
+ (10) mount source: filesystem specific information or "none" |
|
| 33 |
+ (11) super options: per super block options |
|
| 34 |
+ */ |
|
| 28 | 35 |
|
| 29 |
-// Parse /proc/self/mountinfo because comparing Dev and ino does not work from |
|
| 30 |
-// bind mounts |
|
| 31 |
-func parseMountTable() ([]*Info, error) {
|
|
| 32 |
- f, err := os.Open("/proc/self/mountinfo")
|
|
| 33 |
- if err != nil {
|
|
| 34 |
- return nil, err |
|
| 35 |
- } |
|
| 36 |
- defer f.Close() |
|
| 36 |
+ text := s.Text() |
|
| 37 |
+ fields := strings.Split(text, " ") |
|
| 38 |
+ numFields := len(fields) |
|
| 39 |
+ if numFields < 10 {
|
|
| 40 |
+ // should be at least 10 fields |
|
| 41 |
+ return nil, fmt.Errorf("Parsing '%s' failed: not enough fields (%d)", text, numFields)
|
|
| 42 |
+ } |
|
| 37 | 43 |
|
| 38 |
- return parseInfoFile(f) |
|
| 39 |
-} |
|
| 44 |
+ p := &Info{}
|
|
| 45 |
+ // ignore any numbers parsing errors, as there should not be any |
|
| 46 |
+ p.ID, _ = strconv.Atoi(fields[0]) |
|
| 47 |
+ p.Parent, _ = strconv.Atoi(fields[1]) |
|
| 48 |
+ mm := strings.Split(fields[2], ":") |
|
| 49 |
+ if len(mm) != 2 {
|
|
| 50 |
+ return nil, fmt.Errorf("Parsing '%s' failed: unexpected minor:major pair %s", text, mm)
|
|
| 51 |
+ } |
|
| 52 |
+ p.Major, _ = strconv.Atoi(mm[0]) |
|
| 53 |
+ p.Minor, _ = strconv.Atoi(mm[1]) |
|
| 40 | 54 |
|
| 41 |
-func parseInfoFile(r io.Reader) ([]*Info, error) {
|
|
| 42 |
- var ( |
|
| 43 |
- s = bufio.NewScanner(r) |
|
| 44 |
- out = []*Info{}
|
|
| 45 |
- ) |
|
| 55 |
+ p.Root = fields[3] |
|
| 56 |
+ p.Mountpoint = fields[4] |
|
| 57 |
+ p.Opts = fields[5] |
|
| 46 | 58 |
|
| 47 |
- for s.Scan() {
|
|
| 48 |
- if err := s.Err(); err != nil {
|
|
| 49 |
- return nil, err |
|
| 59 |
+ var skip, stop bool |
|
| 60 |
+ if filter != nil {
|
|
| 61 |
+ // filter out entries we're not interested in |
|
| 62 |
+ skip, stop = filter(p) |
|
| 63 |
+ if skip {
|
|
| 64 |
+ continue |
|
| 65 |
+ } |
|
| 50 | 66 |
} |
| 51 | 67 |
|
| 52 |
- var ( |
|
| 53 |
- p = &Info{}
|
|
| 54 |
- text = s.Text() |
|
| 55 |
- optionalFields string |
|
| 56 |
- ) |
|
| 57 |
- |
|
| 58 |
- if _, err := fmt.Sscanf(text, mountinfoFormat, |
|
| 59 |
- &p.ID, &p.Parent, &p.Major, &p.Minor, |
|
| 60 |
- &p.Root, &p.Mountpoint, &p.Opts, &optionalFields); err != nil {
|
|
| 61 |
- return nil, fmt.Errorf("Scanning '%s' failed: %s", text, err)
|
|
| 68 |
+ // one or more optional fields, when a separator (-) |
|
| 69 |
+ i := 6 |
|
| 70 |
+ for ; i < numFields && fields[i] != "-"; i++ {
|
|
| 71 |
+ switch i {
|
|
| 72 |
+ case 6: |
|
| 73 |
+ p.Optional = fields[6] |
|
| 74 |
+ default: |
|
| 75 |
+ /* NOTE there might be more optional fields before the such as |
|
| 76 |
+ fields[7]...fields[N] (where N < sepIndex), although |
|
| 77 |
+ as of Linux kernel 4.15 the only known ones are |
|
| 78 |
+ mount propagation flags in fields[6]. The correct |
|
| 79 |
+ behavior is to ignore any unknown optional fields. |
|
| 80 |
+ */ |
|
| 81 |
+ break |
|
| 82 |
+ } |
|
| 62 | 83 |
} |
| 63 |
- // Safe as mountinfo encodes mountpoints with spaces as \040. |
|
| 64 |
- index := strings.Index(text, " - ") |
|
| 65 |
- postSeparatorFields := strings.Fields(text[index+3:]) |
|
| 66 |
- if len(postSeparatorFields) < 3 {
|
|
| 67 |
- return nil, fmt.Errorf("Error found less than 3 fields post '-' in %q", text)
|
|
| 84 |
+ if i == numFields {
|
|
| 85 |
+ return nil, fmt.Errorf("Parsing '%s' failed: missing separator ('-')", text)
|
|
| 68 | 86 |
} |
| 69 | 87 |
|
| 70 |
- if optionalFields != "-" {
|
|
| 71 |
- p.Optional = optionalFields |
|
| 88 |
+ // There should be 3 fields after the separator... |
|
| 89 |
+ if i+4 > numFields {
|
|
| 90 |
+ return nil, fmt.Errorf("Parsing '%s' failed: not enough fields after a separator", text)
|
|
| 72 | 91 |
} |
| 92 |
+ // ... but in Linux <= 3.9 mounting a cifs with spaces in a share name |
|
| 93 |
+ // (like "//serv/My Documents") _may_ end up having a space in the last field |
|
| 94 |
+ // of mountinfo (like "unc=//serv/My Documents"). Since kernel 3.10-rc1, cifs |
|
| 95 |
+ // option unc= is ignored, so a space should not appear. In here we ignore |
|
| 96 |
+ // those "extra" fields caused by extra spaces. |
|
| 97 |
+ p.Fstype = fields[i+1] |
|
| 98 |
+ p.Source = fields[i+2] |
|
| 99 |
+ p.VfsOpts = fields[i+3] |
|
| 73 | 100 |
|
| 74 |
- p.Fstype = postSeparatorFields[0] |
|
| 75 |
- p.Source = postSeparatorFields[1] |
|
| 76 |
- p.VfsOpts = strings.Join(postSeparatorFields[2:], " ") |
|
| 77 | 101 |
out = append(out, p) |
| 102 |
+ if stop {
|
|
| 103 |
+ break |
|
| 104 |
+ } |
|
| 78 | 105 |
} |
| 79 | 106 |
return out, nil |
| 80 | 107 |
} |
| 81 | 108 |
|
| 109 |
+// Parse /proc/self/mountinfo because comparing Dev and ino does not work from |
|
| 110 |
+// bind mounts |
|
| 111 |
+func parseMountTable(filter FilterFunc) ([]*Info, error) {
|
|
| 112 |
+ f, err := os.Open("/proc/self/mountinfo")
|
|
| 113 |
+ if err != nil {
|
|
| 114 |
+ return nil, err |
|
| 115 |
+ } |
|
| 116 |
+ defer f.Close() |
|
| 117 |
+ |
|
| 118 |
+ return parseInfoFile(f, filter) |
|
| 119 |
+} |
|
| 120 |
+ |
|
| 82 | 121 |
// PidMountInfo collects the mounts for a specific process ID. If the process |
| 83 | 122 |
// ID is unknown, it is better to use `GetMounts` which will inspect |
| 84 | 123 |
// "/proc/self/mountinfo" instead. |
| ... | ... |
@@ -89,5 +128,5 @@ func PidMountInfo(pid int) ([]*Info, error) {
|
| 89 | 89 |
} |
| 90 | 90 |
defer f.Close() |
| 91 | 91 |
|
| 92 |
- return parseInfoFile(f) |
|
| 92 |
+ return parseInfoFile(f, nil) |
|
| 93 | 93 |
} |
| ... | ... |
@@ -5,67 +5,69 @@ package mount // import "github.com/docker/docker/pkg/mount" |
| 5 | 5 |
import ( |
| 6 | 6 |
"bytes" |
| 7 | 7 |
"testing" |
| 8 |
+ |
|
| 9 |
+ "github.com/gotestyourself/gotestyourself/assert" |
|
| 8 | 10 |
) |
| 9 | 11 |
|
| 10 | 12 |
const ( |
| 11 | 13 |
fedoraMountinfo = `15 35 0:3 / /proc rw,nosuid,nodev,noexec,relatime shared:5 - proc proc rw |
| 12 |
- 16 35 0:14 / /sys rw,nosuid,nodev,noexec,relatime shared:6 - sysfs sysfs rw,seclabel |
|
| 13 |
- 17 35 0:5 / /dev rw,nosuid shared:2 - devtmpfs devtmpfs rw,seclabel,size=8056484k,nr_inodes=2014121,mode=755 |
|
| 14 |
- 18 16 0:15 / /sys/kernel/security rw,nosuid,nodev,noexec,relatime shared:7 - securityfs securityfs rw |
|
| 15 |
- 19 16 0:13 / /sys/fs/selinux rw,relatime shared:8 - selinuxfs selinuxfs rw |
|
| 16 |
- 20 17 0:16 / /dev/shm rw,nosuid,nodev shared:3 - tmpfs tmpfs rw,seclabel |
|
| 17 |
- 21 17 0:10 / /dev/pts rw,nosuid,noexec,relatime shared:4 - devpts devpts rw,seclabel,gid=5,mode=620,ptmxmode=000 |
|
| 18 |
- 22 35 0:17 / /run rw,nosuid,nodev shared:21 - tmpfs tmpfs rw,seclabel,mode=755 |
|
| 19 |
- 23 16 0:18 / /sys/fs/cgroup rw,nosuid,nodev,noexec shared:9 - tmpfs tmpfs rw,seclabel,mode=755 |
|
| 20 |
- 24 23 0:19 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime shared:10 - cgroup cgroup rw,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd |
|
| 21 |
- 25 16 0:20 / /sys/fs/pstore rw,nosuid,nodev,noexec,relatime shared:20 - pstore pstore rw |
|
| 22 |
- 26 23 0:21 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:11 - cgroup cgroup rw,cpuset,clone_children |
|
| 23 |
- 27 23 0:22 / /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:12 - cgroup cgroup rw,cpuacct,cpu,clone_children |
|
| 24 |
- 28 23 0:23 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:13 - cgroup cgroup rw,memory,clone_children |
|
| 25 |
- 29 23 0:24 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:14 - cgroup cgroup rw,devices,clone_children |
|
| 26 |
- 30 23 0:25 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime shared:15 - cgroup cgroup rw,freezer,clone_children |
|
| 27 |
- 31 23 0:26 / /sys/fs/cgroup/net_cls rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,net_cls,clone_children |
|
| 28 |
- 32 23 0:27 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime shared:17 - cgroup cgroup rw,blkio,clone_children |
|
| 29 |
- 33 23 0:28 / /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime shared:18 - cgroup cgroup rw,perf_event,clone_children |
|
| 30 |
- 34 23 0:29 / /sys/fs/cgroup/hugetlb rw,nosuid,nodev,noexec,relatime shared:19 - cgroup cgroup rw,hugetlb,clone_children |
|
| 31 |
- 35 1 253:2 / / rw,relatime shared:1 - ext4 /dev/mapper/ssd-root--f20 rw,seclabel,data=ordered |
|
| 32 |
- 36 15 0:30 / /proc/sys/fs/binfmt_misc rw,relatime shared:22 - autofs systemd-1 rw,fd=38,pgrp=1,timeout=300,minproto=5,maxproto=5,direct |
|
| 33 |
- 37 17 0:12 / /dev/mqueue rw,relatime shared:23 - mqueue mqueue rw,seclabel |
|
| 34 |
- 38 35 0:31 / /tmp rw shared:24 - tmpfs tmpfs rw,seclabel |
|
| 35 |
- 39 17 0:32 / /dev/hugepages rw,relatime shared:25 - hugetlbfs hugetlbfs rw,seclabel |
|
| 36 |
- 40 16 0:7 / /sys/kernel/debug rw,relatime shared:26 - debugfs debugfs rw |
|
| 37 |
- 41 16 0:33 / /sys/kernel/config rw,relatime shared:27 - configfs configfs rw |
|
| 38 |
- 42 35 0:34 / /var/lib/nfs/rpc_pipefs rw,relatime shared:28 - rpc_pipefs sunrpc rw |
|
| 39 |
- 43 15 0:35 / /proc/fs/nfsd rw,relatime shared:29 - nfsd sunrpc rw |
|
| 40 |
- 45 35 8:17 / /boot rw,relatime shared:30 - ext4 /dev/sdb1 rw,seclabel,data=ordered |
|
| 41 |
- 46 35 253:4 / /home rw,relatime shared:31 - ext4 /dev/mapper/ssd-home rw,seclabel,data=ordered |
|
| 42 |
- 47 35 253:5 / /var/lib/libvirt/images rw,noatime,nodiratime shared:32 - ext4 /dev/mapper/ssd-virt rw,seclabel,discard,data=ordered |
|
| 43 |
- 48 35 253:12 / /mnt/old rw,relatime shared:33 - ext4 /dev/mapper/HelpDeskRHEL6-FedoraRoot rw,seclabel,data=ordered |
|
| 44 |
- 121 22 0:36 / /run/user/1000/gvfs rw,nosuid,nodev,relatime shared:104 - fuse.gvfsd-fuse gvfsd-fuse rw,user_id=1000,group_id=1000 |
|
| 45 |
- 124 16 0:37 / /sys/fs/fuse/connections rw,relatime shared:107 - fusectl fusectl rw |
|
| 46 |
- 165 38 253:3 / /tmp/mnt rw,relatime shared:147 - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered |
|
| 47 |
- 167 35 253:15 / /var/lib/docker/devicemapper/mnt/aae4076022f0e2b80a2afbf8fc6df450c52080191fcef7fb679a73e6f073e5c2 rw,relatime shared:149 - ext4 /dev/mapper/docker-253:2-425882-aae4076022f0e2b80a2afbf8fc6df450c52080191fcef7fb679a73e6f073e5c2 rw,seclabel,discard,stripe=16,data=ordered |
|
| 48 |
- 171 35 253:16 / /var/lib/docker/devicemapper/mnt/c71be651f114db95180e472f7871b74fa597ee70a58ccc35cb87139ddea15373 rw,relatime shared:153 - ext4 /dev/mapper/docker-253:2-425882-c71be651f114db95180e472f7871b74fa597ee70a58ccc35cb87139ddea15373 rw,seclabel,discard,stripe=16,data=ordered |
|
| 49 |
- 175 35 253:17 / /var/lib/docker/devicemapper/mnt/1bac6ab72862d2d5626560df6197cf12036b82e258c53d981fa29adce6f06c3c rw,relatime shared:157 - ext4 /dev/mapper/docker-253:2-425882-1bac6ab72862d2d5626560df6197cf12036b82e258c53d981fa29adce6f06c3c rw,seclabel,discard,stripe=16,data=ordered |
|
| 50 |
- 179 35 253:18 / /var/lib/docker/devicemapper/mnt/d710a357d77158e80d5b2c55710ae07c94e76d34d21ee7bae65ce5418f739b09 rw,relatime shared:161 - ext4 /dev/mapper/docker-253:2-425882-d710a357d77158e80d5b2c55710ae07c94e76d34d21ee7bae65ce5418f739b09 rw,seclabel,discard,stripe=16,data=ordered |
|
| 51 |
- 183 35 253:19 / /var/lib/docker/devicemapper/mnt/6479f52366114d5f518db6837254baab48fab39f2ac38d5099250e9a6ceae6c7 rw,relatime shared:165 - ext4 /dev/mapper/docker-253:2-425882-6479f52366114d5f518db6837254baab48fab39f2ac38d5099250e9a6ceae6c7 rw,seclabel,discard,stripe=16,data=ordered |
|
| 52 |
- 187 35 253:20 / /var/lib/docker/devicemapper/mnt/8d9df91c4cca5aef49eeb2725292aab324646f723a7feab56be34c2ad08268e1 rw,relatime shared:169 - ext4 /dev/mapper/docker-253:2-425882-8d9df91c4cca5aef49eeb2725292aab324646f723a7feab56be34c2ad08268e1 rw,seclabel,discard,stripe=16,data=ordered |
|
| 53 |
- 191 35 253:21 / /var/lib/docker/devicemapper/mnt/c8240b768603d32e920d365dc9d1dc2a6af46cd23e7ae819947f969e1b4ec661 rw,relatime shared:173 - ext4 /dev/mapper/docker-253:2-425882-c8240b768603d32e920d365dc9d1dc2a6af46cd23e7ae819947f969e1b4ec661 rw,seclabel,discard,stripe=16,data=ordered |
|
| 54 |
- 195 35 253:22 / /var/lib/docker/devicemapper/mnt/2eb3a01278380bbf3ed12d86ac629eaa70a4351301ee307a5cabe7b5f3b1615f rw,relatime shared:177 - ext4 /dev/mapper/docker-253:2-425882-2eb3a01278380bbf3ed12d86ac629eaa70a4351301ee307a5cabe7b5f3b1615f rw,seclabel,discard,stripe=16,data=ordered |
|
| 55 |
- 199 35 253:23 / /var/lib/docker/devicemapper/mnt/37a17fb7c9d9b80821235d5f2662879bd3483915f245f9b49cdaa0e38779b70b rw,relatime shared:181 - ext4 /dev/mapper/docker-253:2-425882-37a17fb7c9d9b80821235d5f2662879bd3483915f245f9b49cdaa0e38779b70b rw,seclabel,discard,stripe=16,data=ordered |
|
| 56 |
- 203 35 253:24 / /var/lib/docker/devicemapper/mnt/aea459ae930bf1de913e2f29428fd80ee678a1e962d4080019d9f9774331ee2b rw,relatime shared:185 - ext4 /dev/mapper/docker-253:2-425882-aea459ae930bf1de913e2f29428fd80ee678a1e962d4080019d9f9774331ee2b rw,seclabel,discard,stripe=16,data=ordered |
|
| 57 |
- 207 35 253:25 / /var/lib/docker/devicemapper/mnt/928ead0bc06c454bd9f269e8585aeae0a6bd697f46dc8754c2a91309bc810882 rw,relatime shared:189 - ext4 /dev/mapper/docker-253:2-425882-928ead0bc06c454bd9f269e8585aeae0a6bd697f46dc8754c2a91309bc810882 rw,seclabel,discard,stripe=16,data=ordered |
|
| 58 |
- 211 35 253:26 / /var/lib/docker/devicemapper/mnt/0f284d18481d671644706e7a7244cbcf63d590d634cc882cb8721821929d0420 rw,relatime shared:193 - ext4 /dev/mapper/docker-253:2-425882-0f284d18481d671644706e7a7244cbcf63d590d634cc882cb8721821929d0420 rw,seclabel,discard,stripe=16,data=ordered |
|
| 59 |
- 215 35 253:27 / /var/lib/docker/devicemapper/mnt/d9dd16722ab34c38db2733e23f69e8f4803ce59658250dd63e98adff95d04919 rw,relatime shared:197 - ext4 /dev/mapper/docker-253:2-425882-d9dd16722ab34c38db2733e23f69e8f4803ce59658250dd63e98adff95d04919 rw,seclabel,discard,stripe=16,data=ordered |
|
| 60 |
- 219 35 253:28 / /var/lib/docker/devicemapper/mnt/bc4500479f18c2c08c21ad5282e5f826a016a386177d9874c2764751c031d634 rw,relatime shared:201 - ext4 /dev/mapper/docker-253:2-425882-bc4500479f18c2c08c21ad5282e5f826a016a386177d9874c2764751c031d634 rw,seclabel,discard,stripe=16,data=ordered |
|
| 61 |
- 223 35 253:29 / /var/lib/docker/devicemapper/mnt/7770c8b24eb3d5cc159a065910076938910d307ab2f5d94e1dc3b24c06ee2c8a rw,relatime shared:205 - ext4 /dev/mapper/docker-253:2-425882-7770c8b24eb3d5cc159a065910076938910d307ab2f5d94e1dc3b24c06ee2c8a rw,seclabel,discard,stripe=16,data=ordered |
|
| 62 |
- 227 35 253:30 / /var/lib/docker/devicemapper/mnt/c280cd3d0bf0aa36b478b292279671624cceafc1a67eaa920fa1082601297adf rw,relatime shared:209 - ext4 /dev/mapper/docker-253:2-425882-c280cd3d0bf0aa36b478b292279671624cceafc1a67eaa920fa1082601297adf rw,seclabel,discard,stripe=16,data=ordered |
|
| 63 |
- 231 35 253:31 / /var/lib/docker/devicemapper/mnt/8b59a7d9340279f09fea67fd6ad89ddef711e9e7050eb647984f8b5ef006335f rw,relatime shared:213 - ext4 /dev/mapper/docker-253:2-425882-8b59a7d9340279f09fea67fd6ad89ddef711e9e7050eb647984f8b5ef006335f rw,seclabel,discard,stripe=16,data=ordered |
|
| 64 |
- 235 35 253:32 / /var/lib/docker/devicemapper/mnt/1a28059f29eda821578b1bb27a60cc71f76f846a551abefabce6efd0146dce9f rw,relatime shared:217 - ext4 /dev/mapper/docker-253:2-425882-1a28059f29eda821578b1bb27a60cc71f76f846a551abefabce6efd0146dce9f rw,seclabel,discard,stripe=16,data=ordered |
|
| 65 |
- 239 35 253:33 / /var/lib/docker/devicemapper/mnt/e9aa60c60128cad1 rw,relatime shared:221 - ext4 /dev/mapper/docker-253:2-425882-e9aa60c60128cad1 rw,seclabel,discard,stripe=16,data=ordered |
|
| 66 |
- 243 35 253:34 / /var/lib/docker/devicemapper/mnt/5fec11304b6f4713fea7b6ccdcc1adc0a1966187f590fe25a8227428a8df275d-init rw,relatime shared:225 - ext4 /dev/mapper/docker-253:2-425882-5fec11304b6f4713fea7b6ccdcc1adc0a1966187f590fe25a8227428a8df275d-init rw,seclabel,discard,stripe=16,data=ordered |
|
| 67 |
- 247 35 253:35 / /var/lib/docker/devicemapper/mnt/5fec11304b6f4713fea7b6ccdcc1adc0a1966187f590fe25a8227428a8df275d rw,relatime shared:229 - ext4 /dev/mapper/docker-253:2-425882-5fec11304b6f4713fea7b6ccdcc1adc0a1966187f590fe25a8227428a8df275d rw,seclabel,discard,stripe=16,data=ordered |
|
| 68 |
- 31 21 0:23 / /DATA/foo_bla_bla rw,relatime - cifs //foo/BLA\040BLA\040BLA/ rw,sec=ntlm,cache=loose,unc=\\foo\BLA BLA BLA,username=my_login,domain=mydomain.com,uid=12345678,forceuid,gid=12345678,forcegid,addr=10.1.30.10,file_mode=0755,dir_mode=0755,nounix,rsize=61440,wsize=65536,actimeo=1` |
|
| 14 |
+16 35 0:14 / /sys rw,nosuid,nodev,noexec,relatime shared:6 - sysfs sysfs rw,seclabel |
|
| 15 |
+17 35 0:5 / /dev rw,nosuid shared:2 - devtmpfs devtmpfs rw,seclabel,size=8056484k,nr_inodes=2014121,mode=755 |
|
| 16 |
+18 16 0:15 / /sys/kernel/security rw,nosuid,nodev,noexec,relatime shared:7 - securityfs securityfs rw |
|
| 17 |
+19 16 0:13 / /sys/fs/selinux rw,relatime shared:8 - selinuxfs selinuxfs rw |
|
| 18 |
+20 17 0:16 / /dev/shm rw,nosuid,nodev shared:3 - tmpfs tmpfs rw,seclabel |
|
| 19 |
+21 17 0:10 / /dev/pts rw,nosuid,noexec,relatime shared:4 - devpts devpts rw,seclabel,gid=5,mode=620,ptmxmode=000 |
|
| 20 |
+22 35 0:17 / /run rw,nosuid,nodev shared:21 - tmpfs tmpfs rw,seclabel,mode=755 |
|
| 21 |
+23 16 0:18 / /sys/fs/cgroup rw,nosuid,nodev,noexec shared:9 - tmpfs tmpfs rw,seclabel,mode=755 |
|
| 22 |
+24 23 0:19 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime shared:10 - cgroup cgroup rw,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd |
|
| 23 |
+25 16 0:20 / /sys/fs/pstore rw,nosuid,nodev,noexec,relatime shared:20 - pstore pstore rw |
|
| 24 |
+26 23 0:21 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:11 - cgroup cgroup rw,cpuset,clone_children |
|
| 25 |
+27 23 0:22 / /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:12 - cgroup cgroup rw,cpuacct,cpu,clone_children |
|
| 26 |
+28 23 0:23 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:13 - cgroup cgroup rw,memory,clone_children |
|
| 27 |
+29 23 0:24 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:14 - cgroup cgroup rw,devices,clone_children |
|
| 28 |
+30 23 0:25 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime shared:15 - cgroup cgroup rw,freezer,clone_children |
|
| 29 |
+31 23 0:26 / /sys/fs/cgroup/net_cls rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,net_cls,clone_children |
|
| 30 |
+32 23 0:27 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime shared:17 - cgroup cgroup rw,blkio,clone_children |
|
| 31 |
+33 23 0:28 / /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime shared:18 - cgroup cgroup rw,perf_event,clone_children |
|
| 32 |
+34 23 0:29 / /sys/fs/cgroup/hugetlb rw,nosuid,nodev,noexec,relatime shared:19 - cgroup cgroup rw,hugetlb,clone_children |
|
| 33 |
+35 1 253:2 / / rw,relatime shared:1 - ext4 /dev/mapper/ssd-root--f20 rw,seclabel,data=ordered |
|
| 34 |
+36 15 0:30 / /proc/sys/fs/binfmt_misc rw,relatime shared:22 - autofs systemd-1 rw,fd=38,pgrp=1,timeout=300,minproto=5,maxproto=5,direct |
|
| 35 |
+37 17 0:12 / /dev/mqueue rw,relatime shared:23 - mqueue mqueue rw,seclabel |
|
| 36 |
+38 35 0:31 / /tmp rw shared:24 - tmpfs tmpfs rw,seclabel |
|
| 37 |
+39 17 0:32 / /dev/hugepages rw,relatime shared:25 - hugetlbfs hugetlbfs rw,seclabel |
|
| 38 |
+40 16 0:7 / /sys/kernel/debug rw,relatime shared:26 - debugfs debugfs rw |
|
| 39 |
+41 16 0:33 / /sys/kernel/config rw,relatime shared:27 - configfs configfs rw |
|
| 40 |
+42 35 0:34 / /var/lib/nfs/rpc_pipefs rw,relatime shared:28 - rpc_pipefs sunrpc rw |
|
| 41 |
+43 15 0:35 / /proc/fs/nfsd rw,relatime shared:29 - nfsd sunrpc rw |
|
| 42 |
+45 35 8:17 / /boot rw,relatime shared:30 - ext4 /dev/sdb1 rw,seclabel,data=ordered |
|
| 43 |
+46 35 253:4 / /home rw,relatime shared:31 - ext4 /dev/mapper/ssd-home rw,seclabel,data=ordered |
|
| 44 |
+47 35 253:5 / /var/lib/libvirt/images rw,noatime,nodiratime shared:32 - ext4 /dev/mapper/ssd-virt rw,seclabel,discard,data=ordered |
|
| 45 |
+48 35 253:12 / /mnt/old rw,relatime shared:33 - ext4 /dev/mapper/HelpDeskRHEL6-FedoraRoot rw,seclabel,data=ordered |
|
| 46 |
+121 22 0:36 / /run/user/1000/gvfs rw,nosuid,nodev,relatime shared:104 - fuse.gvfsd-fuse gvfsd-fuse rw,user_id=1000,group_id=1000 |
|
| 47 |
+124 16 0:37 / /sys/fs/fuse/connections rw,relatime shared:107 - fusectl fusectl rw |
|
| 48 |
+165 38 253:3 / /tmp/mnt rw,relatime shared:147 - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered |
|
| 49 |
+167 35 253:15 / /var/lib/docker/devicemapper/mnt/aae4076022f0e2b80a2afbf8fc6df450c52080191fcef7fb679a73e6f073e5c2 rw,relatime shared:149 - ext4 /dev/mapper/docker-253:2-425882-aae4076022f0e2b80a2afbf8fc6df450c52080191fcef7fb679a73e6f073e5c2 rw,seclabel,discard,stripe=16,data=ordered |
|
| 50 |
+171 35 253:16 / /var/lib/docker/devicemapper/mnt/c71be651f114db95180e472f7871b74fa597ee70a58ccc35cb87139ddea15373 rw,relatime shared:153 - ext4 /dev/mapper/docker-253:2-425882-c71be651f114db95180e472f7871b74fa597ee70a58ccc35cb87139ddea15373 rw,seclabel,discard,stripe=16,data=ordered |
|
| 51 |
+175 35 253:17 / /var/lib/docker/devicemapper/mnt/1bac6ab72862d2d5626560df6197cf12036b82e258c53d981fa29adce6f06c3c rw,relatime shared:157 - ext4 /dev/mapper/docker-253:2-425882-1bac6ab72862d2d5626560df6197cf12036b82e258c53d981fa29adce6f06c3c rw,seclabel,discard,stripe=16,data=ordered |
|
| 52 |
+179 35 253:18 / /var/lib/docker/devicemapper/mnt/d710a357d77158e80d5b2c55710ae07c94e76d34d21ee7bae65ce5418f739b09 rw,relatime shared:161 - ext4 /dev/mapper/docker-253:2-425882-d710a357d77158e80d5b2c55710ae07c94e76d34d21ee7bae65ce5418f739b09 rw,seclabel,discard,stripe=16,data=ordered |
|
| 53 |
+183 35 253:19 / /var/lib/docker/devicemapper/mnt/6479f52366114d5f518db6837254baab48fab39f2ac38d5099250e9a6ceae6c7 rw,relatime shared:165 - ext4 /dev/mapper/docker-253:2-425882-6479f52366114d5f518db6837254baab48fab39f2ac38d5099250e9a6ceae6c7 rw,seclabel,discard,stripe=16,data=ordered |
|
| 54 |
+187 35 253:20 / /var/lib/docker/devicemapper/mnt/8d9df91c4cca5aef49eeb2725292aab324646f723a7feab56be34c2ad08268e1 rw,relatime shared:169 - ext4 /dev/mapper/docker-253:2-425882-8d9df91c4cca5aef49eeb2725292aab324646f723a7feab56be34c2ad08268e1 rw,seclabel,discard,stripe=16,data=ordered |
|
| 55 |
+191 35 253:21 / /var/lib/docker/devicemapper/mnt/c8240b768603d32e920d365dc9d1dc2a6af46cd23e7ae819947f969e1b4ec661 rw,relatime shared:173 - ext4 /dev/mapper/docker-253:2-425882-c8240b768603d32e920d365dc9d1dc2a6af46cd23e7ae819947f969e1b4ec661 rw,seclabel,discard,stripe=16,data=ordered |
|
| 56 |
+195 35 253:22 / /var/lib/docker/devicemapper/mnt/2eb3a01278380bbf3ed12d86ac629eaa70a4351301ee307a5cabe7b5f3b1615f rw,relatime shared:177 - ext4 /dev/mapper/docker-253:2-425882-2eb3a01278380bbf3ed12d86ac629eaa70a4351301ee307a5cabe7b5f3b1615f rw,seclabel,discard,stripe=16,data=ordered |
|
| 57 |
+199 35 253:23 / /var/lib/docker/devicemapper/mnt/37a17fb7c9d9b80821235d5f2662879bd3483915f245f9b49cdaa0e38779b70b rw,relatime shared:181 - ext4 /dev/mapper/docker-253:2-425882-37a17fb7c9d9b80821235d5f2662879bd3483915f245f9b49cdaa0e38779b70b rw,seclabel,discard,stripe=16,data=ordered |
|
| 58 |
+203 35 253:24 / /var/lib/docker/devicemapper/mnt/aea459ae930bf1de913e2f29428fd80ee678a1e962d4080019d9f9774331ee2b rw,relatime shared:185 - ext4 /dev/mapper/docker-253:2-425882-aea459ae930bf1de913e2f29428fd80ee678a1e962d4080019d9f9774331ee2b rw,seclabel,discard,stripe=16,data=ordered |
|
| 59 |
+207 35 253:25 / /var/lib/docker/devicemapper/mnt/928ead0bc06c454bd9f269e8585aeae0a6bd697f46dc8754c2a91309bc810882 rw,relatime shared:189 - ext4 /dev/mapper/docker-253:2-425882-928ead0bc06c454bd9f269e8585aeae0a6bd697f46dc8754c2a91309bc810882 rw,seclabel,discard,stripe=16,data=ordered |
|
| 60 |
+211 35 253:26 / /var/lib/docker/devicemapper/mnt/0f284d18481d671644706e7a7244cbcf63d590d634cc882cb8721821929d0420 rw,relatime shared:193 - ext4 /dev/mapper/docker-253:2-425882-0f284d18481d671644706e7a7244cbcf63d590d634cc882cb8721821929d0420 rw,seclabel,discard,stripe=16,data=ordered |
|
| 61 |
+215 35 253:27 / /var/lib/docker/devicemapper/mnt/d9dd16722ab34c38db2733e23f69e8f4803ce59658250dd63e98adff95d04919 rw,relatime shared:197 - ext4 /dev/mapper/docker-253:2-425882-d9dd16722ab34c38db2733e23f69e8f4803ce59658250dd63e98adff95d04919 rw,seclabel,discard,stripe=16,data=ordered |
|
| 62 |
+219 35 253:28 / /var/lib/docker/devicemapper/mnt/bc4500479f18c2c08c21ad5282e5f826a016a386177d9874c2764751c031d634 rw,relatime shared:201 - ext4 /dev/mapper/docker-253:2-425882-bc4500479f18c2c08c21ad5282e5f826a016a386177d9874c2764751c031d634 rw,seclabel,discard,stripe=16,data=ordered |
|
| 63 |
+223 35 253:29 / /var/lib/docker/devicemapper/mnt/7770c8b24eb3d5cc159a065910076938910d307ab2f5d94e1dc3b24c06ee2c8a rw,relatime shared:205 - ext4 /dev/mapper/docker-253:2-425882-7770c8b24eb3d5cc159a065910076938910d307ab2f5d94e1dc3b24c06ee2c8a rw,seclabel,discard,stripe=16,data=ordered |
|
| 64 |
+227 35 253:30 / /var/lib/docker/devicemapper/mnt/c280cd3d0bf0aa36b478b292279671624cceafc1a67eaa920fa1082601297adf rw,relatime shared:209 - ext4 /dev/mapper/docker-253:2-425882-c280cd3d0bf0aa36b478b292279671624cceafc1a67eaa920fa1082601297adf rw,seclabel,discard,stripe=16,data=ordered |
|
| 65 |
+231 35 253:31 / /var/lib/docker/devicemapper/mnt/8b59a7d9340279f09fea67fd6ad89ddef711e9e7050eb647984f8b5ef006335f rw,relatime shared:213 - ext4 /dev/mapper/docker-253:2-425882-8b59a7d9340279f09fea67fd6ad89ddef711e9e7050eb647984f8b5ef006335f rw,seclabel,discard,stripe=16,data=ordered |
|
| 66 |
+235 35 253:32 / /var/lib/docker/devicemapper/mnt/1a28059f29eda821578b1bb27a60cc71f76f846a551abefabce6efd0146dce9f rw,relatime shared:217 - ext4 /dev/mapper/docker-253:2-425882-1a28059f29eda821578b1bb27a60cc71f76f846a551abefabce6efd0146dce9f rw,seclabel,discard,stripe=16,data=ordered |
|
| 67 |
+239 35 253:33 / /var/lib/docker/devicemapper/mnt/e9aa60c60128cad1 rw,relatime shared:221 - ext4 /dev/mapper/docker-253:2-425882-e9aa60c60128cad1 rw,seclabel,discard,stripe=16,data=ordered |
|
| 68 |
+243 35 253:34 / /var/lib/docker/devicemapper/mnt/5fec11304b6f4713fea7b6ccdcc1adc0a1966187f590fe25a8227428a8df275d-init rw,relatime shared:225 - ext4 /dev/mapper/docker-253:2-425882-5fec11304b6f4713fea7b6ccdcc1adc0a1966187f590fe25a8227428a8df275d-init rw,seclabel,discard,stripe=16,data=ordered |
|
| 69 |
+247 35 253:35 / /var/lib/docker/devicemapper/mnt/5fec11304b6f4713fea7b6ccdcc1adc0a1966187f590fe25a8227428a8df275d rw,relatime shared:229 - ext4 /dev/mapper/docker-253:2-425882-5fec11304b6f4713fea7b6ccdcc1adc0a1966187f590fe25a8227428a8df275d rw,seclabel,discard,stripe=16,data=ordered |
|
| 70 |
+31 21 0:23 / /DATA/foo_bla_bla rw,relatime - cifs //foo/BLA\040BLA\040BLA/ rw,sec=ntlm,cache=loose,unc=\\foo\BLA BLA BLA,username=my_login,domain=mydomain.com,uid=12345678,forceuid,gid=12345678,forcegid,addr=10.1.30.10,file_mode=0755,dir_mode=0755,nounix,rsize=61440,wsize=65536,actimeo=1` |
|
| 69 | 71 |
|
| 70 | 72 |
ubuntuMountInfo = `15 20 0:14 / /sys rw,nosuid,nodev,noexec,relatime - sysfs sysfs rw |
| 71 | 73 |
16 20 0:3 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw |
| ... | ... |
@@ -424,7 +426,7 @@ const ( |
| 424 | 424 |
|
| 425 | 425 |
func TestParseFedoraMountinfo(t *testing.T) {
|
| 426 | 426 |
r := bytes.NewBuffer([]byte(fedoraMountinfo)) |
| 427 |
- _, err := parseInfoFile(r) |
|
| 427 |
+ _, err := parseInfoFile(r, nil) |
|
| 428 | 428 |
if err != nil {
|
| 429 | 429 |
t.Fatal(err) |
| 430 | 430 |
} |
| ... | ... |
@@ -432,7 +434,7 @@ func TestParseFedoraMountinfo(t *testing.T) {
|
| 432 | 432 |
|
| 433 | 433 |
func TestParseUbuntuMountinfo(t *testing.T) {
|
| 434 | 434 |
r := bytes.NewBuffer([]byte(ubuntuMountInfo)) |
| 435 |
- _, err := parseInfoFile(r) |
|
| 435 |
+ _, err := parseInfoFile(r, nil) |
|
| 436 | 436 |
if err != nil {
|
| 437 | 437 |
t.Fatal(err) |
| 438 | 438 |
} |
| ... | ... |
@@ -440,7 +442,7 @@ func TestParseUbuntuMountinfo(t *testing.T) {
|
| 440 | 440 |
|
| 441 | 441 |
func TestParseGentooMountinfo(t *testing.T) {
|
| 442 | 442 |
r := bytes.NewBuffer([]byte(gentooMountinfo)) |
| 443 |
- _, err := parseInfoFile(r) |
|
| 443 |
+ _, err := parseInfoFile(r, nil) |
|
| 444 | 444 |
if err != nil {
|
| 445 | 445 |
t.Fatal(err) |
| 446 | 446 |
} |
| ... | ... |
@@ -448,7 +450,7 @@ func TestParseGentooMountinfo(t *testing.T) {
|
| 448 | 448 |
|
| 449 | 449 |
func TestParseFedoraMountinfoFields(t *testing.T) {
|
| 450 | 450 |
r := bytes.NewBuffer([]byte(fedoraMountinfo)) |
| 451 |
- infos, err := parseInfoFile(r) |
|
| 451 |
+ infos, err := parseInfoFile(r, nil) |
|
| 452 | 452 |
if err != nil {
|
| 453 | 453 |
t.Fatal(err) |
| 454 | 454 |
} |
| ... | ... |
@@ -474,3 +476,33 @@ func TestParseFedoraMountinfoFields(t *testing.T) {
|
| 474 | 474 |
t.Fatalf("expected %#v, got %#v", mi, infos[0])
|
| 475 | 475 |
} |
| 476 | 476 |
} |
| 477 |
+ |
|
| 478 |
+func TestParseMountinfoFilters(t *testing.T) {
|
|
| 479 |
+ r := bytes.NewReader([]byte(fedoraMountinfo)) |
|
| 480 |
+ |
|
| 481 |
+ infos, err := parseInfoFile(r, SingleEntryFilter("/sys/fs/cgroup"))
|
|
| 482 |
+ assert.NilError(t, err) |
|
| 483 |
+ assert.Equal(t, 1, len(infos)) |
|
| 484 |
+ |
|
| 485 |
+ r.Reset([]byte(fedoraMountinfo)) |
|
| 486 |
+ infos, err = parseInfoFile(r, SingleEntryFilter("nonexistent"))
|
|
| 487 |
+ assert.NilError(t, err) |
|
| 488 |
+ assert.Equal(t, 0, len(infos)) |
|
| 489 |
+ |
|
| 490 |
+ r.Reset([]byte(fedoraMountinfo)) |
|
| 491 |
+ infos, err = parseInfoFile(r, PrefixFilter("/sys"))
|
|
| 492 |
+ assert.NilError(t, err) |
|
| 493 |
+ // there are 18 entries starting with /sys in fedoraMountinfo |
|
| 494 |
+ assert.Equal(t, 18, len(infos)) |
|
| 495 |
+ |
|
| 496 |
+ r.Reset([]byte(fedoraMountinfo)) |
|
| 497 |
+ infos, err = parseInfoFile(r, PrefixFilter("nonexistent"))
|
|
| 498 |
+ assert.NilError(t, err) |
|
| 499 |
+ assert.Equal(t, 0, len(infos)) |
|
| 500 |
+ |
|
| 501 |
+ r.Reset([]byte(fedoraMountinfo)) |
|
| 502 |
+ infos, err = parseInfoFile(r, ParentsFilter("/sys/fs/cgroup/cpu,cpuacct"))
|
|
| 503 |
+ assert.NilError(t, err) |
|
| 504 |
+ // there should be 4 results returned: /sys/fs/cgroup/cpu,cpuacct /sys/fs/cgroup /sys / |
|
| 505 |
+ assert.Equal(t, 4, len(infos)) |
|
| 506 |
+} |
| ... | ... |
@@ -19,7 +19,6 @@ import ( |
| 19 | 19 |
"github.com/docker/docker/pkg/mount" |
| 20 | 20 |
"github.com/docker/docker/volume" |
| 21 | 21 |
"github.com/pkg/errors" |
| 22 |
- "github.com/sirupsen/logrus" |
|
| 23 | 22 |
) |
| 24 | 23 |
|
| 25 | 24 |
// VolumeDataPathName is the name of the directory where the volume data is stored. |
| ... | ... |
@@ -66,11 +65,6 @@ func New(scope string, rootIDs idtools.IDPair) (*Root, error) {
|
| 66 | 66 |
return nil, err |
| 67 | 67 |
} |
| 68 | 68 |
|
| 69 |
- mountInfos, err := mount.GetMounts() |
|
| 70 |
- if err != nil {
|
|
| 71 |
- logrus.Debugf("error looking up mounts for local volume cleanup: %v", err)
|
|
| 72 |
- } |
|
| 73 |
- |
|
| 74 | 69 |
for _, d := range dirs {
|
| 75 | 70 |
if !d.IsDir() {
|
| 76 | 71 |
continue |
| ... | ... |
@@ -96,12 +90,7 @@ func New(scope string, rootIDs idtools.IDPair) (*Root, error) {
|
| 96 | 96 |
} |
| 97 | 97 |
|
| 98 | 98 |
// unmount anything that may still be mounted (for example, from an unclean shutdown) |
| 99 |
- for _, info := range mountInfos {
|
|
| 100 |
- if info.Mountpoint == v.path {
|
|
| 101 |
- mount.Unmount(v.path) |
|
| 102 |
- break |
|
| 103 |
- } |
|
| 104 |
- } |
|
| 99 |
+ mount.Unmount(v.path) |
|
| 105 | 100 |
} |
| 106 | 101 |
} |
| 107 | 102 |
|
| ... | ... |
@@ -184,6 +184,10 @@ func TestCreateWithOpts(t *testing.T) {
|
| 184 | 184 |
if runtime.GOOS == "windows" {
|
| 185 | 185 |
t.Skip() |
| 186 | 186 |
} |
| 187 |
+ if os.Getuid() != 0 {
|
|
| 188 |
+ t.Skip("root required")
|
|
| 189 |
+ } |
|
| 190 |
+ |
|
| 187 | 191 |
rootDir, err := ioutil.TempDir("", "local-volume-test")
|
| 188 | 192 |
if err != nil {
|
| 189 | 193 |
t.Fatal(err) |
| ... | ... |
@@ -215,33 +219,27 @@ func TestCreateWithOpts(t *testing.T) {
|
| 215 | 215 |
} |
| 216 | 216 |
}() |
| 217 | 217 |
|
| 218 |
- mountInfos, err := mount.GetMounts() |
|
| 218 |
+ mountInfos, err := mount.GetMounts(mount.SingleEntryFilter(dir)) |
|
| 219 | 219 |
if err != nil {
|
| 220 | 220 |
t.Fatal(err) |
| 221 | 221 |
} |
| 222 |
- |
|
| 223 |
- var found bool |
|
| 224 |
- for _, info := range mountInfos {
|
|
| 225 |
- if info.Mountpoint == dir {
|
|
| 226 |
- found = true |
|
| 227 |
- if info.Fstype != "tmpfs" {
|
|
| 228 |
- t.Fatalf("expected tmpfs mount, got %q", info.Fstype)
|
|
| 229 |
- } |
|
| 230 |
- if info.Source != "tmpfs" {
|
|
| 231 |
- t.Fatalf("expected tmpfs mount, got %q", info.Source)
|
|
| 232 |
- } |
|
| 233 |
- if !strings.Contains(info.VfsOpts, "uid=1000") {
|
|
| 234 |
- t.Fatalf("expected mount info to have uid=1000: %q", info.VfsOpts)
|
|
| 235 |
- } |
|
| 236 |
- if !strings.Contains(info.VfsOpts, "size=1024k") {
|
|
| 237 |
- t.Fatalf("expected mount info to have size=1024k: %q", info.VfsOpts)
|
|
| 238 |
- } |
|
| 239 |
- break |
|
| 240 |
- } |
|
| 222 |
+ if len(mountInfos) != 1 {
|
|
| 223 |
+ t.Fatalf("expected 1 mount, found %d: %+v", len(mountInfos), mountInfos)
|
|
| 241 | 224 |
} |
| 242 | 225 |
|
| 243 |
- if !found {
|
|
| 244 |
- t.Fatal("mount not found")
|
|
| 226 |
+ info := mountInfos[0] |
|
| 227 |
+ t.Logf("%+v", info)
|
|
| 228 |
+ if info.Fstype != "tmpfs" {
|
|
| 229 |
+ t.Fatalf("expected tmpfs mount, got %q", info.Fstype)
|
|
| 230 |
+ } |
|
| 231 |
+ if info.Source != "tmpfs" {
|
|
| 232 |
+ t.Fatalf("expected tmpfs mount, got %q", info.Source)
|
|
| 233 |
+ } |
|
| 234 |
+ if !strings.Contains(info.VfsOpts, "uid=1000") {
|
|
| 235 |
+ t.Fatalf("expected mount info to have uid=1000: %q", info.VfsOpts)
|
|
| 236 |
+ } |
|
| 237 |
+ if !strings.Contains(info.VfsOpts, "size=1024k") {
|
|
| 238 |
+ t.Fatalf("expected mount info to have size=1024k: %q", info.VfsOpts)
|
|
| 245 | 239 |
} |
| 246 | 240 |
|
| 247 | 241 |
if v.active.count != 1 {
|