...
1
2
3
4
19
20 package fs
21
22 import (
23 "fmt"
24 "os"
25 "path/filepath"
26 "syscall"
27 "time"
28
29 "golang.org/x/sys/unix"
30
31 servermetrics "k8s.io/kubernetes/pkg/kubelet/server/metrics"
32 "k8s.io/kubernetes/pkg/volume/util/fsquota"
33 )
34
35 type UsageInfo struct {
36 Bytes int64
37 Inodes int64
38 }
39
40
41
42 func Info(path string) (int64, int64, int64, int64, int64, int64, error) {
43 statfs := &unix.Statfs_t{}
44 err := unix.Statfs(path, statfs)
45 if err != nil {
46 return 0, 0, 0, 0, 0, 0, err
47 }
48
49
50 available := int64(statfs.Bavail) * int64(statfs.Bsize)
51
52
53 capacity := int64(statfs.Blocks) * int64(statfs.Bsize)
54
55
56 usage := (int64(statfs.Blocks) - int64(statfs.Bfree)) * int64(statfs.Bsize)
57
58 inodes := int64(statfs.Files)
59 inodesFree := int64(statfs.Ffree)
60 inodesUsed := inodes - inodesFree
61
62 return available, capacity, usage, inodes, inodesFree, inodesUsed, nil
63 }
64
65
66 func DiskUsage(path string) (UsageInfo, error) {
67 var usage UsageInfo
68
69 if path == "" {
70 return usage, fmt.Errorf("invalid directory")
71 }
72
73
74
75
76 startTime := time.Now()
77 consumption, _ := fsquota.GetConsumption(path)
78 if consumption != nil {
79 usage.Bytes = consumption.Value()
80 defer servermetrics.CollectVolumeStatCalDuration("fsquota", startTime)
81 } else {
82 defer servermetrics.CollectVolumeStatCalDuration("du", startTime)
83 }
84
85 inodes, _ := fsquota.GetInodes(path)
86 if inodes != nil {
87 usage.Inodes = inodes.Value()
88 }
89
90 if inodes != nil && consumption != nil {
91 return usage, nil
92 }
93
94 topLevelStat := &unix.Stat_t{}
95 err := unix.Stat(path, topLevelStat)
96 if err != nil {
97 return usage, err
98 }
99
100
101 dedupedInodes := make(map[uint64]struct{})
102
103 err = filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
104
105 if os.IsNotExist(err) {
106 return nil
107 }
108 if err != nil {
109 return fmt.Errorf("unable to count inodes for %s: %s", path, err)
110 }
111
112
113 if info.Sys() == nil {
114 return fmt.Errorf("fileinfo Sys is nil")
115 }
116
117 s, ok := info.Sys().(*syscall.Stat_t)
118 if !ok {
119 return fmt.Errorf("unsupported fileinfo; could not convert to stat_t")
120 }
121
122 if s.Dev != topLevelStat.Dev {
123
124 return filepath.SkipDir
125 }
126
127
128 if s.Nlink > 1 {
129 if _, ok := dedupedInodes[s.Ino]; !ok {
130 dedupedInodes[s.Ino] = struct{}{}
131 } else {
132 return nil
133 }
134 }
135
136 if consumption == nil {
137 usage.Bytes += int64(s.Blocks) * int64(512)
138 }
139
140 if inodes == nil {
141 usage.Inodes++
142 }
143
144 return nil
145 })
146
147 return usage, err
148 }
149
View as plain text