Limit the default asynchronous queue size based on the maximum file
descriptor limit.

Otherwise, exceeding the FD limit will result in EMFILE errors.

Note that EROFS reuses the file page cache instead of duplicating all
file contents into process memory, though this is constrained by the
maximum FD limit.

Fixes: 9bd592bfed10 ("erofs-utils: mkfs: increase the maximum size of the 
asynchronous queue")
Signed-off-by: Gao Xiang <[email protected]>
---
 configure.ac |  2 ++
 lib/inode.c  | 31 ++++++++++++++++++++++++++++++-
 2 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/configure.ac b/configure.ac
index a73a9ba..5c2737c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -211,6 +211,7 @@ AC_CHECK_HEADERS(m4_flatten([
        sys/ioctl.h
        sys/mman.h
        sys/random.h
+       sys/resource.h
        sys/sendfile.h
        sys/stat.h
        sys/statfs.h
@@ -265,6 +266,7 @@ AC_CHECK_FUNCS(m4_flatten([
        backtrace
        copy_file_range
        fallocate
+       getrlimit
        gettimeofday
        lgetxattr
        llistxattr
diff --git a/lib/inode.c b/lib/inode.c
index 7bd1047..39ffebc 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -1888,6 +1888,28 @@ static int __erofs_mkfs_build_tree(struct 
erofs_mkfs_buildtree_ctx *ctx)
 }
 
 #ifdef EROFS_MT_ENABLED
+
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+static int erofs_get_fdlimit(void)
+{
+#if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT)
+       struct rlimit rlim;
+       int err;
+
+       err = getrlimit(RLIMIT_NOFILE, &rlim);
+       if (err < 0)
+               return _POSIX_OPEN_MAX;
+       if (rlim.rlim_cur == RLIM_INFINITY)
+               return 0;
+       return rlim.rlim_cur;
+#else
+       return _POSIX_OPEN_MAX;
+#endif
+}
+
 static int erofs_mkfs_build_tree(struct erofs_mkfs_buildtree_ctx *ctx)
 {
        struct erofs_mkfs_dfops *q;
@@ -1898,7 +1920,14 @@ static int erofs_mkfs_build_tree(struct 
erofs_mkfs_buildtree_ctx *ctx)
        if (!q)
                return -ENOMEM;
 
-       q->entries = cfg.c_mt_async_queue_limit ?: 32768;
+       if (cfg.c_mt_async_queue_limit) {
+               q->entries = cfg.c_mt_async_queue_limit;
+       } else {
+               err = roundup_pow_of_two(erofs_get_fdlimit()) >> 1;
+               q->entries = err && err < 32768 ? err : 32768;
+       }
+       erofs_dbg("Set the asynchronous queue size to %u", q->entries);
+
        q->queue = malloc(q->entries * sizeof(*q->queue));
        if (!q->queue) {
                free(q);
-- 
2.43.5


Reply via email to