From 1d32c47e68630a410750e82914cc5cf8005b516c Mon Sep 17 00:00:00 2001 From: Euan Kemp Date: Mon, 16 Jan 2017 10:08:02 -0800 Subject: [PATCH] fs: get inodes via pure go instead of find This also makes the count more accurate since hardlinks no longer double-count. --- fs/fs.go | 41 +++++++++++++++-------------------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/fs/fs.go b/fs/fs.go index b78a2e56ec..3644597fae 100644 --- a/fs/fs.go +++ b/fs/fs.go @@ -19,7 +19,6 @@ package fs import ( "bufio" - "bytes" "fmt" "io/ioutil" "os" @@ -474,24 +473,22 @@ func (self *RealFsInfo) GetDirInodeUsage(dir string, timeout time.Duration) (uin if dir == "" { return 0, fmt.Errorf("invalid directory") } - var counter byteCounter - var stderr bytes.Buffer - claimToken() - defer releaseToken() - findCmd := exec.Command("find", dir, "-xdev", "-printf", ".") - findCmd.Stdout, findCmd.Stderr = &counter, &stderr - if err := findCmd.Start(); err != nil { - return 0, fmt.Errorf("failed to exec cmd %v - %v; stderr: %v", findCmd.Args, err, stderr.String()) - } - timer := time.AfterFunc(timeout, func() { - glog.Infof("killing cmd %v due to timeout(%s)", findCmd.Args, timeout.String()) - findCmd.Process.Kill() + + inodes := map[uint64]struct{}{} + + err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return fmt.Errorf("unable to count inodes for part of dir %s: %s", dir, err) + } + s, ok := info.Sys().(*syscall.Stat_t) + if !ok { + return fmt.Errorf("unsupported fileinfo; could not convert to stat_t") + } + inodes[s.Ino] = struct{}{} + return nil }) - if err := findCmd.Wait(); err != nil { - return 0, fmt.Errorf("cmd %v failed. stderr: %s; err: %v", findCmd.Args, stderr.String(), err) - } - timer.Stop() - return counter.bytesWritten, nil + + return uint64(len(inodes)), err } func getVfsStats(path string) (total uint64, free uint64, avail uint64, inodes uint64, inodesFree uint64, err error) { @@ -603,11 +600,3 @@ func getZfstats(poolName string) (uint64, uint64, uint64, error) { return total, dataset.Avail, dataset.Avail, nil } - -// Simple io.Writer implementation that counts how many bytes were written. -type byteCounter struct{ bytesWritten uint64 } - -func (b *byteCounter) Write(p []byte) (int, error) { - b.bytesWritten += uint64(len(p)) - return len(p), nil -}