github.com/tonistiigi/docker@v0.10.1-0.20240229224939-974013b0dc6a/pkg/fileutils/fileutils_linux.go (about) 1 package fileutils 2 3 import ( 4 "context" 5 "fmt" 6 "io" 7 "os" 8 9 "github.com/containerd/containerd/tracing" 10 "github.com/containerd/log" 11 "golang.org/x/sys/unix" 12 ) 13 14 // GetTotalUsedFds Returns the number of used File Descriptors by 15 // reading it via /proc filesystem. 16 func GetTotalUsedFds(ctx context.Context) int { 17 ctx, span := tracing.StartSpan(ctx, "GetTotalUsedFds") 18 defer span.End() 19 20 name := fmt.Sprintf("/proc/%d/fd", os.Getpid()) 21 22 // Fast-path for Linux 6.2 (since [f1f1f2569901ec5b9d425f2e91c09a0e320768f3]). 23 // From the [Linux docs]: 24 // 25 // "The number of open files for the process is stored in 'size' member of 26 // stat() output for /proc/<pid>/fd for fast access." 27 // 28 // [Linux docs]: https://docs.kernel.org/filesystems/proc.html#proc-pid-fd-list-of-symlinks-to-open-files: 29 // [f1f1f2569901ec5b9d425f2e91c09a0e320768f3]: https://github.com/torvalds/linux/commit/f1f1f2569901ec5b9d425f2e91c09a0e320768f3 30 var stat unix.Stat_t 31 if err := unix.Stat(name, &stat); err == nil && stat.Size > 0 { 32 return int(stat.Size) 33 } 34 35 f, err := os.Open(name) 36 if err != nil { 37 log.G(ctx).WithError(err).Error("Error listing file descriptors") 38 return -1 39 } 40 defer f.Close() 41 42 var fdCount int 43 for { 44 select { 45 case <-ctx.Done(): 46 log.G(ctx).WithError(ctx.Err()).Error("Context cancelled while counting file descriptors") 47 return -1 48 default: 49 } 50 51 names, err := f.Readdirnames(100) 52 fdCount += len(names) 53 if err == io.EOF { 54 break 55 } else if err != nil { 56 log.G(ctx).WithError(err).Error("Error listing file descriptors") 57 return -1 58 } 59 } 60 // Note that the slow path has 1 more file-descriptor, due to the open 61 // file-handle for /proc/<pid>/fd during the calculation. 62 return fdCount 63 }