From e02e49c0ffcfe23e5821a0c5216bec730df2c35b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Zaoral?= Date: Tue, 26 Nov 2024 10:19:20 +0100 Subject: [PATCH] Fix affinity mask handling in nproc for large CPU counts Kudos to Florian Weimer for fixing this issue in Fedora! Resolves: RHEL-54139 --- coreutils-nproc-affinity-1.patch | 55 +++++++++++++++++++++++++++ coreutils-nproc-affinity-2.patch | 64 ++++++++++++++++++++++++++++++++ coreutils.spec | 12 +++++- 3 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 coreutils-nproc-affinity-1.patch create mode 100644 coreutils-nproc-affinity-2.patch diff --git a/coreutils-nproc-affinity-1.patch b/coreutils-nproc-affinity-1.patch new file mode 100644 index 0000000..8748d4e --- /dev/null +++ b/coreutils-nproc-affinity-1.patch @@ -0,0 +1,55 @@ +commit 45c2456a56337ebcafe0dd9faa2bd995ccbc3357 +Author: Florian Weimer +Date: Mon Nov 11 14:05:53 2024 +0100 + + nproc: Use affinity mask even on systems with more than 1024 CPUs. + + * lib/nproc.c (num_processors_via_affinity_mask): Retry + with larger affinity masks if CPU_ALLOC_SIZE is available. + +diff --git a/lib/nproc.c b/lib/nproc.c +index 92a07e8289..48bc3d06fa 100644 +--- a/lib/nproc.c ++++ b/lib/nproc.c +@@ -20,6 +20,7 @@ + #include + #include "nproc.h" + ++#include + #include + #include + #include +@@ -124,6 +125,33 @@ num_processors_via_affinity_mask (void) + return count; + } + } ++#elif HAVE_SCHED_GETAFFINITY_LIKE_GLIBC \ ++ && defined CPU_ALLOC_SIZE /* glibc >= 2.6 */ ++ { ++ unsigned int alloc_count = 1024; ++ while (1) ++ { ++ cpu_set_t *set = CPU_ALLOC (alloc_count); ++ if (set == NULL) ++ return 0; ++ unsigned int size = CPU_ALLOC_SIZE (alloc_count); ++ if (sched_getaffinity (0, size, set) == 0) ++ { ++ unsigned int count = CPU_COUNT_S (size, set); ++ CPU_FREE (set); ++ return count; ++ } ++ if (errno != EINVAL) ++ { ++ CPU_FREE (set); ++ return 0; ++ } ++ CPU_FREE (set); ++ alloc_count *= 2; ++ if (alloc_count == 0) ++ return 0; ++ } ++ } + #elif HAVE_SCHED_GETAFFINITY_LIKE_GLIBC /* glibc >= 2.3.4 */ + { + cpu_set_t set; diff --git a/coreutils-nproc-affinity-2.patch b/coreutils-nproc-affinity-2.patch new file mode 100644 index 0000000..aeca09c --- /dev/null +++ b/coreutils-nproc-affinity-2.patch @@ -0,0 +1,64 @@ +commit ee0bc695303775da5026091a65e8ec2b764f4a26 +Author: Bruno Haible +Date: Mon Nov 11 15:40:52 2024 +0100 + + nproc: Use affinity mask even in out-of-memory situations. + + * lib/nproc.c (num_processors_via_affinity_mask): Use a stack-allocated + cpu_set_t as fallback. Add comments. + +diff --git a/lib/nproc.c b/lib/nproc.c +index 48bc3d06fa..0b5898d88f 100644 +--- a/lib/nproc.c ++++ b/lib/nproc.c +@@ -125,15 +125,25 @@ num_processors_via_affinity_mask (void) + return count; + } + } +-#elif HAVE_SCHED_GETAFFINITY_LIKE_GLIBC \ +- && defined CPU_ALLOC_SIZE /* glibc >= 2.6 */ ++#elif HAVE_SCHED_GETAFFINITY_LIKE_GLIBC /* glibc >= 2.3.4 */ ++ /* There are two ways to use the sched_getaffinity() function: ++ - With a statically-sized cpu_set_t. ++ - With a dynamically-sized cpu_set_t. ++ Documentation: ++ ++ ++ The second way has the advantage that it works on systems with more than ++ 1024 CPUs. The first way has the advantage that it works also when memory ++ is tight. */ ++# if defined CPU_ALLOC_SIZE /* glibc >= 2.6 */ + { + unsigned int alloc_count = 1024; +- while (1) ++ for (;;) + { + cpu_set_t *set = CPU_ALLOC (alloc_count); + if (set == NULL) +- return 0; ++ /* Out of memory. */ ++ break; + unsigned int size = CPU_ALLOC_SIZE (alloc_count); + if (sched_getaffinity (0, size, set) == 0) + { +@@ -143,16 +153,19 @@ num_processors_via_affinity_mask (void) + } + if (errno != EINVAL) + { ++ /* Some other error. */ + CPU_FREE (set); + return 0; + } + CPU_FREE (set); ++ /* Retry with some larger cpu_set_t. */ + alloc_count *= 2; + if (alloc_count == 0) ++ /* Integer overflow. Avoid an endless loop. */ + return 0; + } + } +-#elif HAVE_SCHED_GETAFFINITY_LIKE_GLIBC /* glibc >= 2.3.4 */ ++# endif + { + cpu_set_t set; + diff --git a/coreutils.spec b/coreutils.spec index 84dc15a..cfb91f6 100644 --- a/coreutils.spec +++ b/coreutils.spec @@ -1,7 +1,7 @@ Summary: A set of basic GNU tools commonly used in shell scripts Name: coreutils Version: 8.32 -Release: 37%{?dist} +Release: 38%{?dist} License: GPLv3+ Url: https://www.gnu.org/software/coreutils/ Source0: https://ftp.gnu.org/gnu/%{name}/%{name}-%{version}.tar.xz @@ -76,6 +76,11 @@ Patch20: coreutils-8.32-tail-64kpages.patch # fix extended upstream test suite failures (RHEL-60290) Patch21: coreutils-8.32-fix-extended-testsuite.patch +# Fix affinity mask handling in nproc for large CPU counts (RHEL-54139) +# https://bugzilla.redhat.com/show_bug.cgi?id=2325167 +Patch22: coreutils-nproc-affinity-1.patch +Patch23: coreutils-nproc-affinity-2.patch + # disable the test-lock gnulib test prone to deadlock Patch100: coreutils-8.26-test-lock.patch @@ -325,7 +330,10 @@ rm -f $RPM_BUILD_ROOT%{_infodir}/dir %license COPYING %changelog -* Tue Oct 22 2024 Lukáš Zaoral +* Tue Nov 26 2024 Lukáš Zaoral - 8.32-38 +- fix affinity mask handling in nproc for large CPU counts (RHEL-54139) + +* Tue Oct 22 2024 Lukáš Zaoral - 8.32-37 - fix extended upstream test suite failures (RHEL-60290) * Fri Aug 16 2024 Lukáš Zaoral - 8.32-36