[RFC] RLIMIT_NOFILE: the maximum number of open files or the maximum fd index?

From: Nixiaoming
Date: Mon Dec 23 2024 - 20:20:34 EST


I always thought that RLIMIT_NOFILE limits the number of open files, but when I
read the code for alloc_fd(), I found that RLIMIT_NOFILE is the largest fd index?
Is this a mistake in my understanding, or is it a code implementation error?

-----

alloc_fd code:

diff --git a/fs/file.c b/fs/file.c
index fb1011c..e47ddac 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -561,6 +561,7 @@ static int alloc_fd(unsigned start, unsigned end, unsigned flags)
*/
error = -EMFILE;
if (unlikely(fd >= end))
+ // There may be unclosed fd between [end, max]. the number of open files can be greater than RLIMIT_NOFILE.
goto out;

if (unlikely(fd >= fdt->max_fds)) {

-----

Test Procedure
1. ulimit -n 1024.
2. Create 1000 FDs.
3. ulimit -n 100.
4. Close all FDs less than 100 and continue to hold FDs greater than 100.
5. Open() and check whether the FD is successfully created,

If RLIMIT_NOFILE is the upper limit of the number of opened files, step 5 should fail, but step 5 returns success.

-----

test code:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/resource.h>
#include <errno.h>

int main(int argc, char *argv[])
{
int fd, i;
struct rlimit rl;
rl.rlim_cur = 1024;
rl.rlim_max = 1024;

if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
perror("setrlimit");
exit(EXIT_FAILURE);
}

for (i = 0; i < 1000; i++) {
fd = open("/dev/null", O_RDWR | O_CLOEXEC);
if (fd == -1) {
perror("open");
exit(EXIT_FAILURE);
}
}

rl.rlim_cur = 100;
rl.rlim_max = 100;
if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
perror("setrlimit");
exit(EXIT_FAILURE);
}

for (i = 3; i < 100; i++) {
close(i);
}

fd = open("/dev/null", O_RDWR | O_CLOEXEC);
if (fd == -1) {
if (errno == EMFILE) {
printf("ok\n");
return 0;
} else {
perror("open");
exit(EXIT_FAILURE);
}
} else {
printf("fail: {OPEN_MAX} file descriptors are currently open in the calling process, but open() still returns a success\n");
return -1;
}

return 0;
}

----

Best regards,

Xiaoming Ni