diff --git a/fs/fs.go b/fs/fs.go index d8a274a1..4bc39e52 100644 --- a/fs/fs.go +++ b/fs/fs.go @@ -99,34 +99,15 @@ func NewFsInfo(context Context) (FsInfo, error) { if err != nil { return nil, err } + + // Avoid devicemapper container mounts - these are tracked by the ThinPoolWatcher + excluded := []string{fmt.Sprintf("%s/devicemapper/mnt", context.Docker.Root)} fsInfo := &RealFsInfo{ - partitions: make(map[string]partition, 0), + partitions: processMounts(mounts, excluded), labels: make(map[string]string, 0), dmsetup: devicemapper.NewDmsetupClient(), } - supportedFsType := map[string]bool{ - // all ext systems are checked through prefix. - "btrfs": true, - "xfs": true, - "zfs": true, - } - for _, mount := range mounts { - if !strings.HasPrefix(mount.Fstype, "ext") && !supportedFsType[mount.Fstype] { - continue - } - // Avoid bind mounts. - if _, ok := fsInfo.partitions[mount.Source]; ok { - continue - } - fsInfo.partitions[mount.Source] = partition{ - fsType: mount.Fstype, - mountpoint: mount.Mountpoint, - major: uint(mount.Major), - minor: uint(mount.Minor), - } - } - fsInfo.addRktImagesLabel(context, mounts) // need to call this before the log line below printing out the partitions, as this function may // add a "partition" for devicemapper to fsInfo.partitions @@ -137,6 +118,47 @@ func NewFsInfo(context Context) (FsInfo, error) { return fsInfo, nil } +func processMounts(mounts []*mount.Info, excludedMountpointPrefixes []string) map[string]partition { + partitions := make(map[string]partition, 0) + + supportedFsType := map[string]bool{ + // all ext systems are checked through prefix. + "btrfs": true, + "xfs": true, + "zfs": true, + } + + for _, mount := range mounts { + if !strings.HasPrefix(mount.Fstype, "ext") && !supportedFsType[mount.Fstype] { + continue + } + // Avoid bind mounts. + if _, ok := partitions[mount.Source]; ok { + continue + } + + hasPrefix := false + for _, prefix := range excludedMountpointPrefixes { + if strings.HasPrefix(mount.Mountpoint, prefix) { + hasPrefix = true + break + } + } + if hasPrefix { + continue + } + + partitions[mount.Source] = partition{ + fsType: mount.Fstype, + mountpoint: mount.Mountpoint, + major: uint(mount.Major), + minor: uint(mount.Minor), + } + } + + return partitions +} + // getDockerDeviceMapperInfo returns information about the devicemapper device and "partition" if // docker is using devicemapper for its storage driver. If a loopback device is being used, don't // return any information or error, as we want to report based on the actual partition where the diff --git a/fs/fs_test.go b/fs/fs_test.go index 75204e1b..ca9a0777 100644 --- a/fs/fs_test.go +++ b/fs/fs_test.go @@ -432,3 +432,67 @@ func TestAddDockerImagesLabel(t *testing.T) { } } } + +func TestProcessMounts(t *testing.T) { + tests := []struct { + name string + mounts []*mount.Info + excludedPrefixes []string + expected map[string]partition + }{ + { + name: "unsupported fs types", + mounts: []*mount.Info{ + {Fstype: "overlay"}, + {Fstype: "somethingelse"}, + }, + expected: map[string]partition{}, + }, + { + name: "avoid bind mounts", + mounts: []*mount.Info{ + {Root: "/", Mountpoint: "/", Source: "/dev/sda1", Fstype: "xfs", Major: 253, Minor: 0}, + {Root: "/foo", Mountpoint: "/bar", Source: "/dev/sda1", Fstype: "xfs", Major: 253, Minor: 0}, + }, + expected: map[string]partition{ + "/dev/sda1": {fsType: "xfs", mountpoint: "/", major: 253, minor: 0}, + }, + }, + { + name: "exclude prefixes", + mounts: []*mount.Info{ + {Root: "/", Mountpoint: "/someother", Source: "/dev/sda1", Fstype: "xfs", Major: 253, Minor: 2}, + {Root: "/", Mountpoint: "/", Source: "/dev/sda2", Fstype: "xfs", Major: 253, Minor: 0}, + {Root: "/", Mountpoint: "/excludeme", Source: "/dev/sda3", Fstype: "xfs", Major: 253, Minor: 1}, + }, + excludedPrefixes: []string{"/exclude", "/some"}, + expected: map[string]partition{ + "/dev/sda2": {fsType: "xfs", mountpoint: "/", major: 253, minor: 0}, + }, + }, + { + name: "supported fs types", + mounts: []*mount.Info{ + {Root: "/", Mountpoint: "/a", Source: "/dev/sda", Fstype: "ext3", Major: 253, Minor: 0}, + {Root: "/", Mountpoint: "/b", Source: "/dev/sdb", Fstype: "ext4", Major: 253, Minor: 1}, + {Root: "/", Mountpoint: "/c", Source: "/dev/sdc", Fstype: "btrfs", Major: 253, Minor: 2}, + {Root: "/", Mountpoint: "/d", Source: "/dev/sdd", Fstype: "xfs", Major: 253, Minor: 3}, + {Root: "/", Mountpoint: "/e", Source: "/dev/sde", Fstype: "zfs", Major: 253, Minor: 4}, + }, + expected: map[string]partition{ + "/dev/sda": {fsType: "ext3", mountpoint: "/a", major: 253, minor: 0}, + "/dev/sdb": {fsType: "ext4", mountpoint: "/b", major: 253, minor: 1}, + "/dev/sdc": {fsType: "btrfs", mountpoint: "/c", major: 253, minor: 2}, + "/dev/sdd": {fsType: "xfs", mountpoint: "/d", major: 253, minor: 3}, + "/dev/sde": {fsType: "zfs", mountpoint: "/e", major: 253, minor: 4}, + }, + }, + } + + for _, test := range tests { + actual := processMounts(test.mounts, test.excludedPrefixes) + if !reflect.DeepEqual(test.expected, actual) { + t.Errorf("%s: expected %#v, got %#v", test.name, test.expected, actual) + } + } +}