From 0f9a3f756b9adeb8326e0fe7ee7771b16003a019 Mon Sep 17 00:00:00 2001 From: Davanum Srinivas Date: Tue, 21 Jan 2020 10:28:19 -0500 Subject: [PATCH] Split MajorMinor into two fields this reflects what is in the docker/docker/pkg/mount API. makes it easier to port additional code to out API. --- mount_helper_unix.go | 24 +++++++- mount_helper_unix_test.go | 113 ++++++++++++++++++++++++++++++++++++-- mount_linux.go | 10 ++-- 3 files changed, 134 insertions(+), 13 deletions(-) diff --git a/mount_helper_unix.go b/mount_helper_unix.go index 9c91e158264..1e14d8c96ca 100644 --- a/mount_helper_unix.go +++ b/mount_helper_unix.go @@ -61,8 +61,12 @@ type MountInfo struct { ID int // The ID of the parent mount (or of self for the root of this mount namespace's mount tree). ParentID int - // The value of `st_dev` for files on this filesystem. - MajorMinor string + // Major indicates one half of the device ID which identifies the device class + // (parsed from `st_dev` for files on this filesystem). + Major int + // Minor indicates one half of the device ID which identifies a specific + // instance of device (parsed from `st_dev` for files on this filesystem). + Minor int // The pathname of the directory in the filesystem which forms the root of this mount. Root string // Mount source, filesystem-specific information. e.g. device, tmpfs name. @@ -106,10 +110,24 @@ func ParseMountInfo(filename string) ([]MountInfo, error) { if err != nil { return nil, err } + mm := strings.Split(fields[2], ":") + if len(mm) != 2 { + return nil, fmt.Errorf("parsing '%s' failed: unexpected minor:major pair %s", line, mm) + } + major, err := strconv.Atoi(mm[0]) + if err != nil { + return nil, fmt.Errorf("parsing '%s' failed: unable to parse major device id, err:%v", mm[0], err) + } + minor, err := strconv.Atoi(mm[1]) + if err != nil { + return nil, fmt.Errorf("parsing '%s' failed: unable to parse minor device id, err:%v", mm[1], err) + } + info := MountInfo{ ID: id, ParentID: parentID, - MajorMinor: fields[2], + Major: major, + Minor: minor, Root: fields[3], MountPoint: fields[4], MountOptions: strings.Split(fields[5], ","), diff --git a/mount_helper_unix_test.go b/mount_helper_unix_test.go index f364b02863c..af263dbab30 100644 --- a/mount_helper_unix_test.go +++ b/mount_helper_unix_test.go @@ -100,7 +100,8 @@ func TestParseMountInfo(t *testing.T) { MountInfo{ ID: 189, ParentID: 80, - MajorMinor: "8:1", + Major: 8, + Minor: 1, Root: "/var/lib/kubelet", Source: "/dev/sda1", MountPoint: "/var/lib/kubelet", @@ -116,7 +117,8 @@ func TestParseMountInfo(t *testing.T) { MountInfo{ ID: 222, ParentID: 24, - MajorMinor: "253:0", + Major: 253, + Minor: 0, Root: "/tmp/src", Source: "/dev/mapper/vagrant--vg-root", MountPoint: "/mnt/dst", @@ -132,7 +134,8 @@ func TestParseMountInfo(t *testing.T) { MountInfo{ ID: 224, ParentID: 62, - MajorMinor: "253:0", + Major: 253, + Minor: 0, Root: "/var/lib/docker/devicemapper/test/shared", Source: "/dev/mapper/ssd-root", MountPoint: "/var/lib/docker/devicemapper/test/shared", @@ -148,7 +151,8 @@ func TestParseMountInfo(t *testing.T) { MountInfo{ ID: 28, ParentID: 18, - MajorMinor: "0:24", + Major: 0, + Minor: 24, Root: "/", Source: "tmpfs", MountPoint: "/sys/fs/cgroup", @@ -164,7 +168,8 @@ func TestParseMountInfo(t *testing.T) { MountInfo{ ID: 29, ParentID: 28, - MajorMinor: "0:25", + Major: 0, + Minor: 25, Root: "/", Source: "cgroup", MountPoint: "/sys/fs/cgroup/systemd", @@ -180,7 +185,8 @@ func TestParseMountInfo(t *testing.T) { MountInfo{ ID: 31, ParentID: 28, - MajorMinor: "0:27", + Major: 0, + Minor: 27, Root: "/", Source: "cgroup", MountPoint: "/sys/fs/cgroup/cpuset", @@ -213,3 +219,98 @@ func TestParseMountInfo(t *testing.T) { } } } + +func TestBadParseMountInfo(t *testing.T) { + tests := []struct { + info string + name string + id int + expectedInfo *MountInfo + error string + }{ + { + `224 62 253:0 /var/lib/docker/devicemapper/test/shared /var/lib/docker/devicemapper/test/shared rw,relatime master:1 shared:44 - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered`, + "good major:minor field", + 224, + &MountInfo{ + ID: 224, + ParentID: 62, + Major: 253, + Minor: 0, + Root: "/var/lib/docker/devicemapper/test/shared", + Source: "/dev/mapper/ssd-root", + MountPoint: "/var/lib/docker/devicemapper/test/shared", + OptionalFields: []string{"master:1", "shared:44"}, + FsType: "ext4", + MountOptions: []string{"rw", "relatime"}, + SuperOptions: []string{"rw", "seclabel", "data=ordered"}, + }, + "", + }, + { + `224 62 /var/lib/docker/devicemapper/test/shared /var/lib/docker/devicemapper/test/shared rw,relatime master:1 shared:44 - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered`, + "missing major:minor field", + 224, + nil, + `parsing '224 62 /var/lib/docker/devicemapper/test/shared /var/lib/docker/devicemapper/test/shared rw,relatime master:1 shared:44 - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered' failed: unexpected minor:major pair [/var/lib/docker/devicemapper/test/shared]`, + }, + { + `224 62 :0 /var/lib/docker/devicemapper/test/shared /var/lib/docker/devicemapper/test/shared rw,relatime master:1 shared:44 - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered`, + "empty major field", + 224, + nil, + `parsing '' failed: unable to parse major device id, err:strconv.Atoi: parsing "": invalid syntax`, + }, + { + `224 62 253: /var/lib/docker/devicemapper/test/shared /var/lib/docker/devicemapper/test/shared rw,relatime master:1 shared:44 - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered`, + "empty minor field", + 224, + nil, + `parsing '' failed: unable to parse minor device id, err:strconv.Atoi: parsing "": invalid syntax`, + }, + { + `224 62 foo:0 /var/lib/docker/devicemapper/test/shared /var/lib/docker/devicemapper/test/shared rw,relatime master:1 shared:44 - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered`, + "alphabet in major field", + 224, + nil, + `parsing 'foo' failed: unable to parse major device id, err:strconv.Atoi: parsing "foo": invalid syntax`, + }, + { + `224 62 253:bar /var/lib/docker/devicemapper/test/shared /var/lib/docker/devicemapper/test/shared rw,relatime master:1 shared:44 - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered`, + "alphabet in minor field", + 224, + nil, + `parsing 'bar' failed: unable to parse minor device id, err:strconv.Atoi: parsing "bar": invalid syntax`, + }, + } + + for _, test := range tests { + tempDir, filename, err := writeFile(test.info) + if err != nil { + t.Fatalf("cannot create temporary file: %v", err) + } + defer os.RemoveAll(tempDir) + + infos, err := ParseMountInfo(filename) + if err != nil { + if err.Error() != test.error { + t.Errorf("Test case %q:\n expected error: %+v\n got: %+v", test.name, test.error, err.Error()) + } + continue + } + + found := false + for _, info := range infos { + if info.ID == test.id { + found = true + if !reflect.DeepEqual(info, *test.expectedInfo) { + t.Errorf("Test case %q:\n expected: %+v\n got: %+v", test.name, test.expectedInfo, info) + } + break + } + } + if !found { + t.Errorf("Test case %q: mountPoint %d not found", test.name, test.id) + } + } +} diff --git a/mount_linux.go b/mount_linux.go index 88a46424bd7..b9405ba12e9 100644 --- a/mount_linux.go +++ b/mount_linux.go @@ -499,7 +499,8 @@ func SearchMountPoints(hostSource, mountInfoPath string) ([]string, error) { mountID := 0 rootPath := "" - majorMinor := "" + major := -1 + minor := -1 // Finding the underlying root path and major:minor if possible. // We need search in backward order because it's possible for later mounts @@ -509,12 +510,13 @@ func SearchMountPoints(hostSource, mountInfoPath string) ([]string, error) { // If it's a mount point or path under a mount point. mountID = mis[i].ID rootPath = filepath.Join(mis[i].Root, strings.TrimPrefix(hostSource, mis[i].MountPoint)) - majorMinor = mis[i].MajorMinor + major = mis[i].Major + minor = mis[i].Minor break } } - if rootPath == "" || majorMinor == "" { + if rootPath == "" || major == -1 || minor == -1 { return nil, fmt.Errorf("failed to get root path and major:minor for %s", hostSource) } @@ -524,7 +526,7 @@ func SearchMountPoints(hostSource, mountInfoPath string) ([]string, error) { // Ignore mount entry for mount source itself. continue } - if mis[i].Root == rootPath && mis[i].MajorMinor == majorMinor { + if mis[i].Root == rootPath && mis[i].Major == major && mis[i].Minor == minor { refs = append(refs, mis[i].MountPoint) } }