Operations 12 min read

Understanding and Resolving the “Too Many Open Files” Error on Linux

This article explains why the “Too many open files” error occurs on Linux, analyzes the three related kernel parameters (fs.nr_open, nofile, and fs.file-max), shows the relevant source code, and provides step‑by‑step configuration guidance to safely increase file descriptor limits.

Refining Core Development Skills
Refining Core Development Skills
Refining Core Development Skills
Understanding and Resolving the “Too Many Open Files” Error on Linux

If your project handles high concurrency you may have encountered the "Too many open files" error, which occurs because each opened file or socket consumes a file descriptor and Linux limits the number of descriptors per process and system‑wide.

1. Locate the source code

To understand the limits we examine the kernel source for the socket system call and the functions it invokes.

//file: net/socket.c
SYSCALL_DEFINE3(socket, int family, int type, int protocol)
{
    retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK));
    if (retval < 0)
        goto out_release;
}

The call eventually reaches sock_map_fd :

//file: net/socket.c
static int sock_map_fd(struct socket *sock, int flags)
{
    struct file *newfile;
    // check against soft nofile and fs.nr_open
    int fd = get_unused_fd_flags(flags);
    if (unlikely(fd < 0))
        return fd;
    // check against fs.file-max
    newfile = sock_alloc_file(sock, flags, NULL);
    if (likely(!IS_ERR(newfile))) {
        fd_install(fd, newfile);
        return fd;
    }
    put_unused_fd(fd);
    return PTR_ERR(newfile);
}

The kernel uses two different objects: an integer file descriptor (fd) and a full struct file object created by sock_alloc_file . The following diagram (original image) illustrates the relationship.

get_unused_fd_flags: allocates a numeric fd (just an array index).

sock_alloc_file: allocates the actual kernel file object.

2. Process‑level limits: nofile and fs.nr_open

The function get_unused_fd_flags checks the per‑process limit RLIMIT_NOFILE , which corresponds to the soft nofile value from /etc/security/limits.conf :

//file: fs/file.c
int get_unused_fd_flags(unsigned flags)
{
    // RLIMIT_NOFILE is the soft nofile limit
    return __alloc_fd(current->files, 0, rlimit(RLIMIT_NOFILE), flags);
}

Inside __alloc_fd the kernel compares the requested fd against the hard limit (the hard nofile value) and returns -EMFILE if it would exceed it.

//file: include/uapi/asm-generic/errno-base.h
#define EMFILE 24 /* Too many open files */

int __alloc_fd(struct files_struct *files, unsigned start, unsigned end, unsigned flags)
{
    // check against hard limit (end)
    if (fd >= end)
        goto out; // will return -EMFILE
    ...
}

The helper expand_files also checks the global kernel parameter fs.nr_open :

static int expand_files(struct files_struct *files, int nr)
{
    // 2. check against fs.nr_open
    if (nr >= sysctl_nr_open)
        return -EMFILE;
}

Both checks use the current process’s fd number, so they are effectively per‑process limits. The difference is that soft nofile can be set per user, while fs.nr_open is a single system‑wide value.

Conclusion 1: soft nofile and fs.nr_open both restrict the maximum number of file descriptors a single process may open; the former is user‑configurable, the latter is global.

3. System‑wide limit: fs.file-max

The function sock_alloc_file eventually calls alloc_file , which checks the total number of open files against fs.file-max :

//file: fs/file_table.c
if (get_nr_files() >= files_stat.max_files && !capable(CAP_SYS_ADMIN)) {
    // non‑root users are limited
}

get_nr_files() returns the total count of open file descriptors in the whole system. The check also excludes processes with the CAP_SYS_ADMIN capability, i.e., the root user.

Conclusion 2: fs.file-max limits the total number of open files on the system but does not apply to the root user.

Summary

Process‑level limits: soft nofile and fs.nr_open (both per‑process). Adjust both; hard nofile must be ≥ soft nofile.

System‑level limit: fs.file-max (system‑wide, root exempt).

When increasing limits, ensure: (1) hard nofile ≥ soft nofile, (2) hard nofile ≤ fs.nr_open, (3) changes to fs.nr_open survive reboots (use /etc/sysctl.conf ).

Example configuration to allow a process to open one million descriptors:

# vi /etc/sysctl.conf
fs.nr_open=1100000   # slightly larger than hard nofile
fs.file-max=1100000  # leave some buffer
# sysctl -p
# vi /etc/security/limits.conf
* soft nofile 1000000
* hard nofile 1000000

After applying these settings, the “Too many open files” error should disappear for non‑root users.

For further discussion, the author invites readers to join a technical group via WeChat or visit the GitHub repository https://github.com/yanfeizhang/coder-kung-fu .

performanceKernellinuxulimitfile descriptorssystem limits
Refining Core Development Skills
Written by

Refining Core Development Skills

Fei has over 10 years of development experience at Tencent and Sogou. Through this account, he shares his deep insights on performance.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.