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