diff --git a/disk/disk_linux.go b/disk/disk_linux.go index 241f6b5328..34d8c3380b 100644 --- a/disk/disk_linux.go +++ b/disk/disk_linux.go @@ -374,14 +374,21 @@ func parseFieldsOnMountinfo(ctx context.Context, lines []string, all bool, filen device = mntSrc } - if _, ok := seenDevIDs[blockDeviceID]; ok { - // Bind mount; set the underlying mount path as the device. - device = seenDevIDs[blockDeviceID] + // Track device paths by block device ID to resolve bind mounts. + // A bind mount is identified by rootDir != "/" (mounting a subdirectory of a filesystem). + // Only apply bind detection for storage-backed filesystems (mntSrc starts with "/"), + // since virtual filesystems (e.g. nsfs) use rootDir for non-path identifiers. + if firstDev, ok := seenDevIDs[blockDeviceID]; ok { + // Same block device seen before - use the original device path. + device = firstDev + } + if strings.HasPrefix(mntSrc, "/") && rootDir != "/" { isBind = true mountOpts = append(mountOpts, "bind") } - - seenDevIDs[blockDeviceID] = mountPoint + if _, ok := seenDevIDs[blockDeviceID]; !ok { + seenDevIDs[blockDeviceID] = device + } if !all && isBind { continue diff --git a/disk/disk_linux_test.go b/disk/disk_linux_test.go index a097ec34de..594c6223e2 100644 --- a/disk/disk_linux_test.go +++ b/disk/disk_linux_test.go @@ -31,7 +31,7 @@ func Test_parseFieldsOnMountinfo(t *testing.T) { expect: []PartitionStat{ {Device: "/dev/sda1", Mountpoint: "/", Fstype: "ext4", Opts: []string{"rw", "noatime"}}, {Device: "/dev/sda2", Mountpoint: "/foo", Fstype: "ext4", Opts: []string{"rw", "noatime"}}, - {Device: "/foo", Mountpoint: "/foo/bar", Fstype: "ext4", Opts: []string{"rw", "noatime", "bind"}}, + {Device: "/dev/sda2", Mountpoint: "/foo/bar", Fstype: "ext4", Opts: []string{"rw", "noatime", "bind"}}, {Device: "-", Mountpoint: "/dev/shm", Fstype: "tmpfs", Opts: []string{"rw", "nosuid", "nodev", "noexec", "relatime"}}, {Device: "net:[12345]", Mountpoint: "/run/netns/foo", Fstype: "nsfs", Opts: []string{"rw"}}, {Device: "sysfs", Mountpoint: "/sys", Fstype: "sysfs", Opts: []string{"rw", "nosuid", "nodev", "noexec", "noatime"}}, @@ -56,6 +56,29 @@ func Test_parseFieldsOnMountinfo(t *testing.T) { } } +func Test_parseFieldsOnMountinfo_multiMount(t *testing.T) { + // Reproduces issue #2005: same block device (259:4) mounted multiple times + // with different rootDirs. Bind mounts should be detected by rootDir != "/", + // not by whether the device ID was seen before. + lines := []string{ + "1204 1184 259:4 /var/lib/kubelet/pods/abc/volumes/tmp /tmp rw,relatime shared:1 - ext4 /dev/nvme0n1p3 rw", + "1205 1184 259:4 /var/lib/kubelet/pods/abc/volumes/config /etc/datadog-agent rw,relatime shared:1 - ext4 /dev/nvme0n1p3 rw", + "1209 1184 259:4 /etc/passwd /etc/passwd ro,relatime shared:1 - ext4 /dev/nvme0n1p3 rw", + "1210 1184 259:4 / /host/root ro,relatime shared:1 - ext4 /dev/nvme0n1p3 rw", + } + + actual, err := parseFieldsOnMountinfo(context.Background(), lines, true, "") + require.NoError(t, err) + + expected := []PartitionStat{ + {Device: "/dev/nvme0n1p3", Mountpoint: "/tmp", Fstype: "ext4", Opts: []string{"rw", "relatime", "bind"}}, + {Device: "/dev/nvme0n1p3", Mountpoint: "/etc/datadog-agent", Fstype: "ext4", Opts: []string{"rw", "relatime", "bind"}}, + {Device: "/dev/nvme0n1p3", Mountpoint: "/etc/passwd", Fstype: "ext4", Opts: []string{"ro", "relatime", "bind"}}, + {Device: "/dev/nvme0n1p3", Mountpoint: "/host/root", Fstype: "ext4", Opts: []string{"ro", "relatime"}}, + } + assert.Equal(t, expected, actual) +} + func Test_parseFieldsOnMounts(t *testing.T) { fs := []string{"sysfs", "tmpfs"}