github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/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/log"
    10  	"golang.org/x/sys/unix"
    11  )
    12  
    13  // GetTotalUsedFds Returns the number of used File Descriptors by
    14  // reading it via /proc filesystem.
    15  func GetTotalUsedFds() int {
    16  	name := fmt.Sprintf("/proc/%d/fd", os.Getpid())
    17  
    18  	// Fast-path for Linux 6.2 (since [f1f1f2569901ec5b9d425f2e91c09a0e320768f3]).
    19  	// From the [Linux docs]:
    20  	//
    21  	// "The number of open files for the process is stored in 'size' member of
    22  	// stat() output for /proc/<pid>/fd for fast access."
    23  	//
    24  	// [Linux docs]: https://docs.kernel.org/filesystems/proc.html#proc-pid-fd-list-of-symlinks-to-open-files:
    25  	// [f1f1f2569901ec5b9d425f2e91c09a0e320768f3]: https://github.com/torvalds/linux/commit/f1f1f2569901ec5b9d425f2e91c09a0e320768f3
    26  	var stat unix.Stat_t
    27  	if err := unix.Stat(name, &stat); err == nil && stat.Size > 0 {
    28  		return int(stat.Size)
    29  	}
    30  
    31  	f, err := os.Open(name)
    32  	if err != nil {
    33  		log.G(context.TODO()).WithError(err).Error("Error listing file descriptors")
    34  		return -1
    35  	}
    36  	defer f.Close()
    37  
    38  	var fdCount int
    39  	for {
    40  		names, err := f.Readdirnames(100)
    41  		fdCount += len(names)
    42  		if err == io.EOF {
    43  			break
    44  		} else if err != nil {
    45  			log.G(context.TODO()).WithError(err).Error("Error listing file descriptors")
    46  			return -1
    47  		}
    48  	}
    49  	// Note that the slow path has 1 more file-descriptor, due to the open
    50  	// file-handle for /proc/<pid>/fd during the calculation.
    51  	return fdCount
    52  }