diff --git a/fs/fs.go b/fs/fs.go index 4e7bde7c..de40d5fd 100644 --- a/fs/fs.go +++ b/fs/fs.go @@ -79,6 +79,8 @@ type RealFsInfo struct { // Map from label to block device path. // Labels are intent-specific tags that are auto-detected. labels map[string]string + // Map from mountpoint to mount information. + mounts map[string]*mount.Info // devicemapper client dmsetup devicemapper.DmsetupClient } @@ -106,9 +108,14 @@ func NewFsInfo(context Context) (FsInfo, error) { fsInfo := &RealFsInfo{ partitions: processMounts(mounts, excluded), labels: make(map[string]string, 0), + mounts: make(map[string]*mount.Info, 0), dmsetup: devicemapper.NewDmsetupClient(), } + for _, mount := range mounts { + fsInfo.mounts[mount.Mountpoint] = mount + } + 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 @@ -153,25 +160,12 @@ func processMounts(mounts []*mount.Info, excludedMountpointPrefixes []string) ma // btrfs fix: following workaround fixes wrong btrfs Major and Minor Ids reported in /proc/self/mountinfo. // instead of using values from /proc/self/mountinfo we use stat to get Ids from btrfs mount point if mount.Fstype == "btrfs" && mount.Major == 0 && strings.HasPrefix(mount.Source, "/dev/") { - - buf := new(syscall.Stat_t) - err := syscall.Stat(mount.Source, buf) + major, minor, err := getBtrfsMajorMinorIds(mount) if err != nil { - glog.Warningf("stat failed on %s with error: %s", mount.Source, err) + glog.Warningf("%s", err) } else { - glog.Infof("btrfs mount %#v", mount) - if buf.Mode&syscall.S_IFMT == syscall.S_IFBLK { - err := syscall.Stat(mount.Mountpoint, buf) - if err != nil { - glog.Warningf("stat failed on %s with error: %s", mount.Mountpoint, err) - } else { - glog.Infof("btrfs dev major:minor %d:%d\n", int(major(buf.Dev)), int(minor(buf.Dev))) - glog.Infof("btrfs rdev major:minor %d:%d\n", int(major(buf.Rdev)), int(minor(buf.Rdev))) - - mount.Major = int(major(buf.Dev)) - mount.Minor = int(minor(buf.Dev)) - } - } + mount.Major = major + mount.Minor = minor } } @@ -445,6 +439,7 @@ func (self *RealFsInfo) GetDirFsDevice(dir string) (*DeviceInfo, error) { if err != nil { return nil, fmt.Errorf("stat failed on %s with error: %s", dir, err) } + major := major(buf.Dev) minor := minor(buf.Dev) for device, partition := range self.partitions { @@ -452,6 +447,16 @@ func (self *RealFsInfo) GetDirFsDevice(dir string) (*DeviceInfo, error) { return &DeviceInfo{device, major, minor}, nil } } + + mount, found := self.mounts[dir] + if found && mount.Fstype == "btrfs" && mount.Major == 0 && strings.HasPrefix(mount.Source, "/dev/") { + major, minor, err := getBtrfsMajorMinorIds(mount) + if err != nil { + glog.Warningf("%s", err) + } else { + return &DeviceInfo{mount.Source, uint(major), uint(minor)}, nil + } + } return nil, fmt.Errorf("could not find device with major: %d, minor: %d in cached partitions map", major, minor) } @@ -645,3 +650,32 @@ func (b *byteCounter) Write(p []byte) (int, error) { b.bytesWritten += uint64(len(p)) return len(p), nil } + +// Get major and minor Ids for a mount point using btrfs as filesystem. +func getBtrfsMajorMinorIds(mount *mount.Info) (int, int, error) { + // btrfs fix: following workaround fixes wrong btrfs Major and Minor Ids reported in /proc/self/mountinfo. + // instead of using values from /proc/self/mountinfo we use stat to get Ids from btrfs mount point + + buf := new(syscall.Stat_t) + err := syscall.Stat(mount.Source, buf) + if err != nil { + err = fmt.Errorf("stat failed on %s with error: %s", mount.Source, err) + return 0, 0, err + } + + glog.Infof("btrfs mount %#v", mount) + if buf.Mode&syscall.S_IFMT == syscall.S_IFBLK { + err := syscall.Stat(mount.Mountpoint, buf) + if err != nil { + err = fmt.Errorf("stat failed on %s with error: %s", mount.Mountpoint, err) + return 0, 0, err + } + + glog.Infof("btrfs dev major:minor %d:%d\n", int(major(buf.Dev)), int(minor(buf.Dev))) + glog.Infof("btrfs rdev major:minor %d:%d\n", int(major(buf.Rdev)), int(minor(buf.Rdev))) + + return int(major(buf.Dev)), int(minor(buf.Dev)), nil + } else { + return 0, 0, fmt.Errorf("%s is not a block device", mount.Source) + } +}