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  }