123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263 |
- package fileutils
- import (
- "context"
- "fmt"
- "io"
- "os"
- "github.com/containerd/containerd/tracing"
- "github.com/containerd/log"
- "golang.org/x/sys/unix"
- )
- // GetTotalUsedFds Returns the number of used File Descriptors by
- // reading it via /proc filesystem.
- func GetTotalUsedFds(ctx context.Context) int {
- ctx, span := tracing.StartSpan(ctx, "GetTotalUsedFds")
- defer span.End()
- name := fmt.Sprintf("/proc/%d/fd", os.Getpid())
- // Fast-path for Linux 6.2 (since [f1f1f2569901ec5b9d425f2e91c09a0e320768f3]).
- // From the [Linux docs]:
- //
- // "The number of open files for the process is stored in 'size' member of
- // stat() output for /proc/<pid>/fd for fast access."
- //
- // [Linux docs]: https://docs.kernel.org/filesystems/proc.html#proc-pid-fd-list-of-symlinks-to-open-files:
- // [f1f1f2569901ec5b9d425f2e91c09a0e320768f3]: https://github.com/torvalds/linux/commit/f1f1f2569901ec5b9d425f2e91c09a0e320768f3
- var stat unix.Stat_t
- if err := unix.Stat(name, &stat); err == nil && stat.Size > 0 {
- return int(stat.Size)
- }
- f, err := os.Open(name)
- if err != nil {
- log.G(ctx).WithError(err).Error("Error listing file descriptors")
- return -1
- }
- defer f.Close()
- var fdCount int
- for {
- select {
- case <-ctx.Done():
- log.G(ctx).WithError(ctx.Err()).Error("Context cancelled while counting file descriptors")
- return -1
- default:
- }
- names, err := f.Readdirnames(100)
- fdCount += len(names)
- if err == io.EOF {
- break
- } else if err != nil {
- log.G(ctx).WithError(err).Error("Error listing file descriptors")
- return -1
- }
- }
- // Note that the slow path has 1 more file-descriptor, due to the open
- // file-handle for /proc/<pid>/fd during the calculation.
- return fdCount
- }
|