* Re: [Pkg-utopia-maintainers] Bug#1070019: udisks2: autopkgtest failure: fsconfig system call failed: /dev/sr1: Can't open blockdev
From: Chris Hofstaedtler @ 2024-04-29 17:52 UTC (permalink / raw)
To: util-linux; +Cc: Michael Biebl, 1070019
In-Reply-To: <ngnnmq6rsi6ohuipejqw4ussgtbur3nab5nnvx3vqrfhlrvfvk@67u5ihxjhcri>
* Chris Hofstaedtler <zeha@debian.org> [240429 15:24]:
> > udisks2's autopkgtest fails when tried together with util-linux 2.40. An
> > example can be seen here:
> > https://ci.debian.net/packages/u/udisks2/testing/amd64/46012968/
> >
> > 537s ======================================================================
> > 537s FAIL: test_ext4 (__main__.FS.test_ext4)
> > 537s fs: ext4
> > 537s ----------------------------------------------------------------------
> > 537s Traceback (most recent call last):
> > 537s File "/tmp/autopkgtest.btnhgm/build.cz4/src/src/tests/integration-test", line 1107, in _do_udisks_check
> > 537s cd_fs.call_mount_sync(ro_options, None)
> > 537s gi.repository.GLib.GError: udisks-error-quark: GDBus.Error:org.freedesktop.UDisks2.Error.Failed: Error mounting /dev/sr1 at /media/root/41b1acb1-744c-422a-9071-2dba5368a683: fsconfig system call failed: /dev/sr1: Can't open blockdev (0)
> > 537s
> > 537s During handling of the above exception, another exception occurred:
> > 537s
> > 537s Traceback (most recent call last):
> > 537s File "/tmp/autopkgtest.btnhgm/build.cz4/src/src/tests/integration-test", line 725, in test_ext4
> > 537s self._do_fs_check('ext4')
> > 537s File "/tmp/autopkgtest.btnhgm/build.cz4/src/src/tests/integration-test", line 894, in _do_fs_check
> > 537s self._do_udisks_check(fs_type)
> > 537s File "/tmp/autopkgtest.btnhgm/build.cz4/src/src/tests/integration-test", line 1112, in _do_udisks_check
> > 537s self.fail('Mounting read-only device with \'rw\' option failed'
> > 537s AssertionError: Mounting read-only device with 'rw' option failedwith an unexpected error.
> > 537s Got: udisks-error-quark: GDBus.Error:org.freedesktop.UDisks2.Error.Failed: Error mounting /dev/sr1 at /media/root/41b1acb1-744c-422a-9071-2dba5368a683: fsconfig system call failed: /dev/sr1: Can't open blockdev (0)
> > 537s Expected: 'is write-protected but explicit read-write mode requested' or 'is write-protected but `rw' option given'
> I won't get to it this week (also re: stable v2.40.1), but maybe
> someone else has seen this failure already?
Having said that, it seems likely the test was broken by this
change in util-linux:
libmount: report kernel message from new API
https://github.com/util-linux/util-linux/commit/9da5644e414cdc318f0311260dabc6035c85b58e
I don't know if the error messages are supposed to be stable or not,
but it looks like a very intentional change :-)
Orthogonally, "/dev/sr1: Can't open blockdev" seems not very
informative if it's supposed to mean "write-protected but `rw'
option given".
Chris
^ permalink raw reply
* Re: [PATCH 1/2] textual: fix some typos and inconsistencies in usage and error messages
From: Benno Schulenberg @ 2024-04-29 14:58 UTC (permalink / raw)
To: Karel Zak; +Cc: util-linux, Petr Pisar
In-Reply-To: <20240429123542.zbiieh6dpux6xoza@ws.net.home>
[-- Attachment #1.1: Type: text/plain, Size: 368 bytes --]
Op 29-04-2024 om 14:35 schreef Karel Zak:
> Applied (to master and stable/v2.40), thanks!
Hmm... I don't think it's a good idea to apply it to the stable/v2.40
branch, as it invalidates any translations that were made for these
strings. It would be okay if you first offer a new POT file to the
TP before making the next stable dot release.
Benno
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]
^ permalink raw reply
* Re: [Pkg-utopia-maintainers] Bug#1070019: udisks2: autopkgtest failure: fsconfig system call failed: /dev/sr1: Can't open blockdev
From: Chris Hofstaedtler @ 2024-04-29 12:58 UTC (permalink / raw)
To: util-linux; +Cc: Michael Biebl, 1070019
In-Reply-To: <9625ca13-a775-4768-b4f1-b2da4de70009@debian.org>
Dear util-linux@,
in Debian, udisks2 2.10.1-6 (autopkg-)tests fail with util-linux
2.40, but passed with 2.39. We are not yet sure if this is directly
caused by util-linux, but it seems somewhat likely.
I won't get to it this week (also re: stable v2.40.1), but maybe
someone else has seen this failure already?
> udisks2's autopkgtest fails when tried together with util-linux 2.40. An
> example can be seen here:
> https://ci.debian.net/packages/u/udisks2/testing/amd64/46012968/
>
> 537s ======================================================================
> 537s FAIL: test_ext4 (__main__.FS.test_ext4)
> 537s fs: ext4
> 537s ----------------------------------------------------------------------
> 537s Traceback (most recent call last):
> 537s File "/tmp/autopkgtest.btnhgm/build.cz4/src/src/tests/integration-test", line 1107, in _do_udisks_check
> 537s cd_fs.call_mount_sync(ro_options, None)
> 537s gi.repository.GLib.GError: udisks-error-quark: GDBus.Error:org.freedesktop.UDisks2.Error.Failed: Error mounting /dev/sr1 at /media/root/41b1acb1-744c-422a-9071-2dba5368a683: fsconfig system call failed: /dev/sr1: Can't open blockdev (0)
> 537s
> 537s During handling of the above exception, another exception occurred:
> 537s
> 537s Traceback (most recent call last):
> 537s File "/tmp/autopkgtest.btnhgm/build.cz4/src/src/tests/integration-test", line 725, in test_ext4
> 537s self._do_fs_check('ext4')
> 537s File "/tmp/autopkgtest.btnhgm/build.cz4/src/src/tests/integration-test", line 894, in _do_fs_check
> 537s self._do_udisks_check(fs_type)
> 537s File "/tmp/autopkgtest.btnhgm/build.cz4/src/src/tests/integration-test", line 1112, in _do_udisks_check
> 537s self.fail('Mounting read-only device with \'rw\' option failed'
> 537s AssertionError: Mounting read-only device with 'rw' option failedwith an unexpected error.
> 537s Got: udisks-error-quark: GDBus.Error:org.freedesktop.UDisks2.Error.Failed: Error mounting /dev/sr1 at /media/root/41b1acb1-744c-422a-9071-2dba5368a683: fsconfig system call failed: /dev/sr1: Can't open blockdev (0)
> 537s Expected: 'is write-protected but explicit read-write mode requested' or 'is write-protected but `rw' option given'
>
> I do not understand what this error means, or what the underlying problem is.
> Please investigate.
For context, Debian's util-linux 2.40-7 should have everything from
2.40 stable up to a8aa0b5f154a44557f5bae5a4027bdbfe42b0323.
Chris
^ permalink raw reply
* v2.40.1 this week
From: Karel Zak @ 2024-04-29 12:38 UTC (permalink / raw)
To: util-linux
Hi all,
I would like to announce the release of v2.40.1 from the
stable/v2.40.1 branch this Thursday or Friday.
Please take the time to test the branch and ensure that it includes
all of the fixes that have been reported and requested.
Thank you.
Karel
--
Karel Zak <kzak@redhat.com>
http://karelzak.blogspot.com
^ permalink raw reply
* Re: [PATCH 1/2] textual: fix some typos and inconsistencies in usage and error messages
From: Karel Zak @ 2024-04-29 12:35 UTC (permalink / raw)
To: Benno Schulenberg; +Cc: util-linux, Petr Pisar
In-Reply-To: <20240326154822.8959-2-bensberg@telfort.nl>
On Tue, Mar 26, 2024 at 04:48:21PM +0100, Benno Schulenberg wrote:
> login-utils/lslogins.c | 2 +-
> misc-utils/lastlog2.c | 2 +-
> misc-utils/lsfd.c | 2 +-
> misc-utils/lslocks.c | 2 +-
> misc-utils/waitpid.c | 2 +-
> sys-utils/irqtop.c | 4 ++--
> sys-utils/setpriv.c | 2 +-
> term-utils/agetty.c | 4 ++--
> 8 files changed, 10 insertions(+), 10 deletions(-)
On Tue, Mar 26, 2024 at 04:48:22PM +0100, Benno Schulenberg wrote:
> misc-utils/lastlog2.c | 18 +++++++++---------
> 1 file changed, 9 insertions(+), 9 deletions(-)
Applied (to master and stable/v2.40), thanks!
Karel
--
Karel Zak <kzak@redhat.com>
http://karelzak.blogspot.com
^ permalink raw reply
* Re: [PATCH v3] flock: add support for using fcntl() with open file description locks
From: Karel Zak @ 2024-04-29 8:29 UTC (permalink / raw)
To: Thomas Weißschuh; +Cc: Rasmus Villemoes, util-linux, Masatake YAMATO
In-Reply-To: <a0de91f6-2eb0-4526-a50a-b89db9fe140f@t-8ch.de>
On Sun, Apr 28, 2024 at 11:07:56PM +0200, Thomas Weißschuh wrote:
> >
> > sys-utils/flock.c | 78 +++++++++++++++++++++++++++++++++++++++++++++--
>
> Some testcases in tests/ts/misc/flock would be nice.
+1
Merged, for tests use another PR.
Karel
--
Karel Zak <kzak@redhat.com>
http://karelzak.blogspot.com
^ permalink raw reply
* Re: [PATCH v12] coresched: Manage core scheduling cookies for tasks
From: Karel Zak @ 2024-04-29 8:28 UTC (permalink / raw)
To: Thomas Weißschuh; +Cc: Thijs Raymakers, util-linux, Phil Auld
In-Reply-To: <73694be2-6215-4baf-8bfa-573cfc2dbfb7@t-8ch.de>
On Fri, Apr 26, 2024 at 08:03:35PM +0200, Thomas Weißschuh wrote:
> Thanks for all the work.
>
> On 2024-04-25 18:22:25+0000, Thijs Raymakers wrote:
> > Co-authored-by: Phil Auld <pauld@redhat.com>
> > Signed-off-by: Phil Auld <pauld@redhat.com>
> > Signed-off-by: Thijs Raymakers <thijs@raymakers.nl>
>
> Reviewed-by: Thomas Weißschuh <thomas@t-8ch.de>
Merged. Thanks!
Karel
--
Karel Zak <kzak@redhat.com>
http://karelzak.blogspot.com
^ permalink raw reply
* Re: [PATCH v3] flock: add support for using fcntl() with open file description locks
From: Thomas Weißschuh @ 2024-04-28 21:07 UTC (permalink / raw)
To: Rasmus Villemoes; +Cc: util-linux, Masatake YAMATO, Karel Zak
In-Reply-To: <20240425094417.1174162-1-rasmus.villemoes@prevas.dk>
On 2024-04-25 11:44:17+0000, Rasmus Villemoes wrote:
> Currently, there is no way for shell scripts to safely access
> resources protected by POSIX locking (fcntl with the F_SETLK/F_SETLKW
> commands). For example, the glibc function lckpwdf(), used to
> protect access to the /etc/shadow database, works by taking a
> F_SETLKW on /etc/.pwd.lock .
>
> Due to the odd semantics of POSIX locking (e.g. released when any file
> descriptor associated to the inode is closed), we cannot usefully
> directly expose the POSIX F_SETLK/F_SETLKW commands. However, linux
> 3.15 introduced F_OFD_SETLK[W], with semantics wrt. ownership and
> release better matching those of flock(2), and crucially they do
> conflict with locks obtained via F_SETLK[W]. With this, a shell script
> can do
>
> exec 4> /etc/.pwd.lock
> flock --fcntl 4
> <access/modify /etc/shadow ...>
> flock --fcntl --unlock 4 # or just exit
>
> without conflicting with passwd(1) or other utilities that
> access/modify /etc/shadow.
>
> No single-letter shorthand is defined for the option, because this is
> somewhat low-level and the user really needs to know what he is doing.
>
> Also, this leaves the door open for teaching --fcntl to accept an
> optional argument: "ofd", the default, and "posix", should anyone find
> a use for flock(1) taking a F_SETLK[W] lock.
>
> Signed-off-by: Rasmus Villemoes <rasmus.villemoes@prevas.dk>
> ---
> v3:
>
> - Replace configure-time checking for F_OFD_ by just hard-coding the
> proper values in flock.c if the system headers don't provide them.
>
> - Consequently, drop all HAVE_FCNTL_OFD_LOCKS guards.
>
> v2:
>
> - Shorten option name to --fcntl instead of --fcntl-ofd.
>
> - Use a do_lock() helper function switching on the API to use, making
> the while () condition easier to read and making it simpler to add
> the mentioned --fcntl=posix should the need arise.
>
> - Fix up places that need HAVE_FCNTL_OFD_LOCKS guarding.
>
> sys-utils/flock.c | 78 +++++++++++++++++++++++++++++++++++++++++++++--
Some testcases in tests/ts/misc/flock would be nice.
> 1 file changed, 76 insertions(+), 2 deletions(-)
>
> diff --git a/sys-utils/flock.c b/sys-utils/flock.c
[..]
^ permalink raw reply
* Re: [PATCH v12] coresched: Manage core scheduling cookies for tasks
From: Thomas Weißschuh @ 2024-04-26 18:03 UTC (permalink / raw)
To: Thijs Raymakers; +Cc: kzak, util-linux, Phil Auld
In-Reply-To: <20240425162226.130639-1-thijs@raymakers.nl>
Thanks for all the work.
On 2024-04-25 18:22:25+0000, Thijs Raymakers wrote:
> Co-authored-by: Phil Auld <pauld@redhat.com>
> Signed-off-by: Phil Auld <pauld@redhat.com>
> Signed-off-by: Thijs Raymakers <thijs@raymakers.nl>
Reviewed-by: Thomas Weißschuh <thomas@t-8ch.de>
> ---
>
> .gitignore | 1 +
> bash-completion/coresched | 0
Don't forget this :-)
> configure.ac | 12 +-
> meson.build | 16 +-
> meson_options.txt | 2 +-
> schedutils/Makemodule.am | 8 +
> schedutils/coresched.1.adoc | 139 +++++++
> schedutils/coresched.c | 363 ++++++++++++++++++
> tests/commands.sh | 1 +
> .../coresched-copy-from-child-to-parent | 1 +
> ...coresched-copy-from-parent-to-nested-child | 1 +
> .../schedutils/coresched-get-cookie-own-pid | 1 +
> .../coresched-get-cookie-parent-pid | 1 +
> .../coresched-new-child-with-new-cookie | 1 +
> .../coresched-set-cookie-parent-pid.err | 1 +
> .../expected/schedutils/set-cookie-parent-pid | 1 +
> tests/ts/schedutils/coresched | 83 ++++
> 17 files changed, 626 insertions(+), 6 deletions(-)
> create mode 100644 bash-completion/coresched
> create mode 100644 schedutils/coresched.1.adoc
> create mode 100644 schedutils/coresched.c
> create mode 100644 tests/expected/schedutils/coresched-copy-from-child-to-parent
> create mode 100644 tests/expected/schedutils/coresched-copy-from-parent-to-nested-child
> create mode 100644 tests/expected/schedutils/coresched-get-cookie-own-pid
> create mode 100644 tests/expected/schedutils/coresched-get-cookie-parent-pid
> create mode 100644 tests/expected/schedutils/coresched-new-child-with-new-cookie
> create mode 100644 tests/expected/schedutils/coresched-set-cookie-parent-pid.err
> create mode 100644 tests/expected/schedutils/set-cookie-parent-pid
> create mode 100755 tests/ts/schedutils/coresched
^ permalink raw reply
* Re: [PATCH v3] flock: add support for using fcntl() with open file description locks
From: Karel Zak @ 2024-04-26 8:01 UTC (permalink / raw)
To: Rasmus Villemoes; +Cc: util-linux, Masatake YAMATO
In-Reply-To: <20240425094417.1174162-1-rasmus.villemoes@prevas.dk>
On Thu, Apr 25, 2024 at 11:44:17AM +0200, Rasmus Villemoes wrote:
> v3:
>
> - Replace configure-time checking for F_OFD_ by just hard-coding the
> proper values in flock.c if the system headers don't provide them.
>
> - Consequently, drop all HAVE_FCNTL_OFD_LOCKS guards.
PR updated: https://github.com/util-linux/util-linux/pull/2993
Karel
--
Karel Zak <kzak@redhat.com>
http://karelzak.blogspot.com
^ permalink raw reply
* Re: [PATCH v12] coresched: Manage core scheduling cookies for tasks
From: Karel Zak @ 2024-04-26 7:59 UTC (permalink / raw)
To: Thijs Raymakers; +Cc: thomas, util-linux, Phil Auld
In-Reply-To: <20240425162226.130639-1-thijs@raymakers.nl>
On Thu, Apr 25, 2024 at 06:22:25PM +0200, Thijs Raymakers wrote:
> I agree, it would be better to handle it there. The error message "No
> device available" you would get otherwise is a bit cryptic so this
> is an improvement.
>
> I've removed the ts_skip and added the case there.
PR updated https://github.com/util-linux/util-linux/pull/2990
Karel
--
Karel Zak <kzak@redhat.com>
http://karelzak.blogspot.com
^ permalink raw reply
* Re: [PATCH v2] flock: add support for using fcntl() with open file description locks
From: Karel Zak @ 2024-04-26 7:57 UTC (permalink / raw)
To: Rasmus Villemoes; +Cc: util-linux, Masatake YAMATO
In-Reply-To: <0ebbe2b6-7f2d-451f-8f43-3765915a462e@prevas.dk>
On Fri, Apr 26, 2024 at 07:55:04AM +0200, Rasmus Villemoes wrote:
> On 25/04/2024 15.55, Karel Zak wrote:
> > On Tue, Apr 23, 2024 at 02:08:19PM +0200, Rasmus Villemoes wrote:
> >> configure.ac | 6 ++++
> >> meson.build | 3 ++
> >> sys-utils/flock.c | 82 +++++++++++++++++++++++++++++++++++++++++++++--
> >> 3 files changed, 89 insertions(+), 2 deletions(-)
> >
> > Thanks, created pull-request to check it by our CI.
> > https://github.com/util-linux/util-linux/pull/2993
>
> Thanks, but I sent a v3 eliding the configure-time checks. Can I get you
> to consider that?
>
> In general, do you prefer PRs, or is using the ML as I've done fine? I
> can do it either way.
If you are able to use PR on Github, it would be easier for me.
However, the mailing list is still a supported option, of course. :-)
Karel
--
Karel Zak <kzak@redhat.com>
http://karelzak.blogspot.com
^ permalink raw reply
* Re: [PATCH v2] flock: add support for using fcntl() with open file description locks
From: Rasmus Villemoes @ 2024-04-26 5:55 UTC (permalink / raw)
To: Karel Zak; +Cc: util-linux, Masatake YAMATO
In-Reply-To: <20240425135522.hu6wrdwoanresvvi@ws.net.home>
On 25/04/2024 15.55, Karel Zak wrote:
> On Tue, Apr 23, 2024 at 02:08:19PM +0200, Rasmus Villemoes wrote:
>> configure.ac | 6 ++++
>> meson.build | 3 ++
>> sys-utils/flock.c | 82 +++++++++++++++++++++++++++++++++++++++++++++--
>> 3 files changed, 89 insertions(+), 2 deletions(-)
>
> Thanks, created pull-request to check it by our CI.
> https://github.com/util-linux/util-linux/pull/2993
Thanks, but I sent a v3 eliding the configure-time checks. Can I get you
to consider that?
In general, do you prefer PRs, or is using the ML as I've done fine? I
can do it either way.
Rasmus
^ permalink raw reply
* [PATCH v12] coresched: Manage core scheduling cookies for tasks
From: Thijs Raymakers @ 2024-04-25 16:22 UTC (permalink / raw)
To: thomas; +Cc: kzak, util-linux, Thijs Raymakers, Phil Auld
In-Reply-To: <295323c3-a43a-4f60-9c71-3b38a19b1d6f@t-8ch.de>
Co-authored-by: Phil Auld <pauld@redhat.com>
Signed-off-by: Phil Auld <pauld@redhat.com>
Signed-off-by: Thijs Raymakers <thijs@raymakers.nl>
---
Hi Thomas,
Op 25-04-2024 om 5:51 p.m. schreef Thomas Weißschuh:
> On 2024-04-25 17:36:26+0000, Thijs Raymakers wrote:
>>+static bool is_core_sched_supported(void)
>>+{
>>+ sched_core_cookie cookie = 0;
>>+ if (prctl(PR_SCHED_CORE, PR_SCHED_CORE_GET, getpid(),
>>+ PR_SCHED_CORE_SCOPE_THREAD, &cookie))
>>+ if (errno == EINVAL)
>>+ return false;
> IMO the ENODEV should be handled here.
> So the user can get a proper error message.
>
> This would then also remove the need for another ts_skip in the
> testcase.
I agree, it would be better to handle it there. The error message "No
device available" you would get otherwise is a bit cryptic so this
is an improvement.
I've removed the ts_skip and added the case there.
Interdiff against v11:
diff --git a/schedutils/coresched.c b/schedutils/coresched.c
index beeb01702..9d8be3e12 100644
--- a/schedutils/coresched.c
+++ b/schedutils/coresched.c
@@ -188,16 +188,21 @@ static void core_sched_exec_with_cookie(struct args *args, char **argv)
errexec(argv[0]);
}
-// If PR_SCHED_CORE is not recognized, or not supported on this system,
-// then prctl will set errno to EINVAL. Assuming all other operands of
-// prctl are valid, we can use errno==EINVAL as a check to see whether
-// core scheduling is available on this system.
+// There are two failure conditions for the core scheduling prctl calls
+// that rely on the environment in which coresched is running.
+// 1. If PR_SCHED_CORE is not recognized, or not supported on this system,
+// then prctl will set errno to EINVAL. Assuming all other operands of
+// prctl are valid, we can use errno==EINVAL as a check to see whether
+// core scheduling is available on this system.
+// 2. prctl sets errno to ENODEV if SMT is not available on this system,
+// either because SMT support has been disabled in the kernel, or because
+// the hardware doesn't support it.
static bool is_core_sched_supported(void)
{
sched_core_cookie cookie = 0;
if (prctl(PR_SCHED_CORE, PR_SCHED_CORE_GET, getpid(),
PR_SCHED_CORE_SCOPE_THREAD, &cookie))
- if (errno == EINVAL)
+ if (errno == EINVAL || errno == ENODEV)
return false;
return true;
@@ -328,8 +333,8 @@ int main(int argc, char **argv)
if (!is_core_sched_supported())
errx(EXIT_FAILURE,
- _("No support for core scheduling found. Does your kernel "
- "support CONFIG_SCHED_CORE?"));
+ _("Core scheduling is not supported on this system. Either SMT "
+ "is unavailable or your kernel does not support CONFIG_SCHED_CORE."));
sched_core_cookie cookie;
diff --git a/tests/ts/schedutils/coresched b/tests/ts/schedutils/coresched
index debb8cbfc..2ab0803bd 100755
--- a/tests/ts/schedutils/coresched
+++ b/tests/ts/schedutils/coresched
@@ -16,16 +16,10 @@ ts_check_test_command "$TS_CMD_CORESCHED"
ts_check_prog "tee"
ts_check_prog "sed"
-# If there is no kernel support, skip the test suite
+# If coresched cannot succesfully run, skip the test suite
CORESCHED_TEST_KERNEL_SUPPORT_CMD=$($TS_CMD_CORESCHED 2>&1)
if [[ $CORESCHED_TEST_KERNEL_SUPPORT_CMD == *"CONFIG_SCHED_CORE"* ]]; then
- ts_skip "Kernel has no CONFIG_SCHED_CORE support"
-fi
-
-# Kernel and the machine must support SMT
-CORESCHED_HAS_SMT_SUPPORT=$(</sys/devices/system/cpu/smt/control)
-if [[ "$CORESCHED_HAS_SMT_SUPPORT" != "on" ]]; then
- ts_skip "SMT is unavailable (state: $CORESCHED_HAS_SMT_SUPPORT)"
+ ts_skip "Kernel has no CONFIG_SCHED_CORE support or SMT is not available"
fi
# The output of coresched contains PIDs and core scheduling cookies, both of which should be
.gitignore | 1 +
bash-completion/coresched | 0
configure.ac | 12 +-
meson.build | 16 +-
meson_options.txt | 2 +-
schedutils/Makemodule.am | 8 +
schedutils/coresched.1.adoc | 139 +++++++
schedutils/coresched.c | 363 ++++++++++++++++++
tests/commands.sh | 1 +
.../coresched-copy-from-child-to-parent | 1 +
...coresched-copy-from-parent-to-nested-child | 1 +
.../schedutils/coresched-get-cookie-own-pid | 1 +
.../coresched-get-cookie-parent-pid | 1 +
.../coresched-new-child-with-new-cookie | 1 +
.../coresched-set-cookie-parent-pid.err | 1 +
.../expected/schedutils/set-cookie-parent-pid | 1 +
tests/ts/schedutils/coresched | 83 ++++
17 files changed, 626 insertions(+), 6 deletions(-)
create mode 100644 bash-completion/coresched
create mode 100644 schedutils/coresched.1.adoc
create mode 100644 schedutils/coresched.c
create mode 100644 tests/expected/schedutils/coresched-copy-from-child-to-parent
create mode 100644 tests/expected/schedutils/coresched-copy-from-parent-to-nested-child
create mode 100644 tests/expected/schedutils/coresched-get-cookie-own-pid
create mode 100644 tests/expected/schedutils/coresched-get-cookie-parent-pid
create mode 100644 tests/expected/schedutils/coresched-new-child-with-new-cookie
create mode 100644 tests/expected/schedutils/coresched-set-cookie-parent-pid.err
create mode 100644 tests/expected/schedutils/set-cookie-parent-pid
create mode 100755 tests/ts/schedutils/coresched
diff --git a/.gitignore b/.gitignore
index 6ecbfa7fe..316f3cdcc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -94,6 +94,7 @@ ylwrap
/colcrt
/colrm
/column
+/coresched
/ctrlaltdel
/delpart
/dmesg
diff --git a/bash-completion/coresched b/bash-completion/coresched
new file mode 100644
index 000000000..e69de29bb
diff --git a/configure.ac b/configure.ac
index 1d7a9cf70..70a60cf5d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2514,9 +2514,9 @@ UL_REQUIRES_HAVE([setterm], [ncursesw, ncurses], [ncursesw or ncurses library])
AM_CONDITIONAL([BUILD_SETTERM], [test "x$build_setterm" = xyes])
# build_schedutils= is just configure-only variable to control
-# ionice, taskset and chrt
+# ionice, taskset, coresched and chrt
AC_ARG_ENABLE([schedutils],
- AS_HELP_STRING([--disable-schedutils], [do not build chrt, ionice, taskset]),
+ AS_HELP_STRING([--disable-schedutils], [do not build chrt, ionice, taskset, coresched]),
[], [UL_DEFAULT_ENABLE([schedutils], [check])]
)
@@ -2559,6 +2559,14 @@ UL_REQUIRES_SYSCALL_CHECK([taskset],
AM_CONDITIONAL([BUILD_TASKSET], [test "x$build_taskset" = xyes])
+UL_ENABLE_ALIAS([coresched], [schedutils])
+UL_BUILD_INIT([coresched])
+UL_REQUIRES_SYSCALL_CHECK([coresched],
+ [UL_CHECK_SYSCALL([prctl])],
+ [prctl])
+AM_CONDITIONAL([BUILD_CORESCHED], [test "x$build_coresched" = xyes])
+
+
have_schedsetter=no
AS_IF([test "x$ac_cv_func_sched_setscheduler" = xyes], [have_schedsetter=yes],
[test "x$ac_cv_func_sched_setattr" = xyes], [have_schedsetter=yes])
diff --git a/meson.build b/meson.build
index 5b4f59b8c..3cfd63449 100644
--- a/meson.build
+++ b/meson.build
@@ -3194,13 +3194,23 @@ exe4 = executable(
install : opt,
build_by_default : opt)
+exe5 = executable(
+ 'coresched',
+ 'schedutils/coresched.c',
+ include_directories : includes,
+ link_with : lib_common,
+ install_dir : usrbin_exec_dir,
+ install : opt,
+ build_by_default : opt)
+
if opt and not is_disabler(exe)
- exes += [exe, exe2, exe3, exe4]
+ exes += [exe, exe2, exe3, exe4, exe5]
manadocs += ['schedutils/chrt.1.adoc',
'schedutils/ionice.1.adoc',
'schedutils/taskset.1.adoc',
- 'schedutils/uclampset.1.adoc']
- bashcompletions += ['chrt', 'ionice', 'taskset', 'uclampset']
+ 'schedutils/uclampset.1.adoc',
+ 'schedutils/coresched.1.adoc']
+ bashcompletions += ['chrt', 'ionice', 'taskset', 'uclampset', 'coresched']
endif
############################################################
diff --git a/meson_options.txt b/meson_options.txt
index ca76530a9..8a70555d7 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -182,7 +182,7 @@ option('build-pipesz', type : 'feature',
option('build-setterm', type : 'feature',
description : 'build setterm')
option('build-schedutils', type : 'feature',
- description : 'build chrt, ionice, taskset')
+ description : 'build chrt, ionice, taskset, coresched')
option('build-wall', type : 'feature',
description : 'build wall')
option('build-write', type : 'feature',
diff --git a/schedutils/Makemodule.am b/schedutils/Makemodule.am
index 1040da85f..0cb655401 100644
--- a/schedutils/Makemodule.am
+++ b/schedutils/Makemodule.am
@@ -29,3 +29,11 @@ dist_noinst_DATA += schedutils/uclampset.1.adoc
uclampset_SOURCES = schedutils/uclampset.c schedutils/sched_attr.h
uclampset_LDADD = $(LDADD) libcommon.la
endif
+
+if BUILD_CORESCHED
+usrbin_exec_PROGRAMS += coresched
+MANPAGES += schedutils/coresched.1
+dist_noinst_DATA += schedutils/coresched.1.adoc
+coresched_SOURCES = schedutils/coresched.c
+coresched_LDADD = $(LDADD) libcommon.la
+endif
diff --git a/schedutils/coresched.1.adoc b/schedutils/coresched.1.adoc
new file mode 100644
index 000000000..8a9c28846
--- /dev/null
+++ b/schedutils/coresched.1.adoc
@@ -0,0 +1,139 @@
+//po4a: entry man manual
+////
+coresched(1) manpage
+////
+= coresched(1)
+:doctype: manpage
+:man manual: User Commands
+:man source: util-linux {release-version}
+:page-layout: base
+:command: coresched
+:colon: :
+:copyright: ©
+
+== NAME
+
+coresched - manage core scheduling cookies for tasks
+
+== SYNOPSIS
+
+*{command}* [*get*] [*-s* _pid_]
+
+*{command}* *new* [*-t* _type_] *-d* _pid_
+
+*{command}* *new* [*-t* _type_] \-- _command_ [_argument_...]
+
+*{command}* *copy* [*-s* _pid_] [*-t* _type_] *-d* _pid_
+
+*{command}* *copy* [*-s* _pid_] [*-t* _type_] \-- _command_ [_argument_...]
+
+== DESCRIPTION
+The *{command}* command is used to retrieve or modify the core scheduling cookies of a running process given its _pid_, or to spawn a new _command_ with core scheduling cookies.
+
+Core scheduling permits the definition of groups of tasks that are allowed to share a physical core.
+This is done by assigning a cookie to each task.
+Only tasks have the same cookie are allowed to be scheduled on the same physical core.
+
+It is possible to either assign a new random cookie to a task, or copy a cookie from another task. It is not possible to choose the value of the cookie.
+
+== FUNCTIONS
+*get*::
+Retrieve the core scheduling cookie of the PID specified in *-s*.
+If *-s* is omitted, it will get the cookie of the current *{command}* process.
+
+*new*::
+Assign a new cookie to an existing PID specified in *-d*, or execute _command_ with a new cookie.
+
+*copy*::
+Copy the cookie from an existing PID (*-s*) to another PID (*-d*), or execute _command_ with that cookie.
+If *-s* is omitted, it will get the cookie of the current *{command}* process.
+
+If no function is specified, it will run the *get* function.
+
+== OPTIONS
+*-s*, *--source* _PID_::
+Which _PID_ to get the cookie from.
+If this option is omitted, it will get the cookie from the current *{command}* process.
+
+*-d*, *--dest* _PID_::
+Which _PID_ to modify the cookie of.
+
+*-t*, *--dest-type* _TYPE_::
+The type of the PID whose cookie will be modified. This can be one of three values:
+- *pid*, or process ID
+- *tgid*, or thread group ID (default value)
+- *pgid*, or process group ID
+
+*-v*, *--verbose*::
+Show extra information when modifying cookies of tasks.
+
+*-h*, *--help*::
+Display help text and exit.
+
+*-V*, *--version*::
+Print version and exit.
+
+== EXAMPLES
+Get the core scheduling cookie of the {command} task itself, usually inherited from its parent{colon}::
+*{command} get*
+
+Get the core scheduling cookie of a task with PID _123_{colon}::
+*{command} get -s* _123_
+
+Give a task with PID _123_ a new core scheduling cookie{colon}::
+*{command} new -d* _123_
+
+Spawn a new task with a new core scheduling cookie{colon}::
+*{command} new* \-- _command_ [_argument_...]
+
+Copy the cookie from the current {command} process another task with pid _456_{colon}::
+*{command} copy -d* _456_
+
+Copy the cookie from a task with pid _123_ to another task with pid _456_{colon}::
+*{command} copy -s* _123_ *-d* _456_
+
+Copy the cookie from a task with pid _123_ to a new task _command_{colon}::
+*{command} copy -s* _123_ \-- _command_ [_argument_...]
+
+Copy the cookie from a task with pid _123_ to the process group ID _456_{colon}::
+*{command} copy -s* _123_ *-t* _pgid_ *-d* _456_
+
+== PERMISSIONS
+Retrieving or modifying the core scheduling cookie of a process requires *PTRACE_MODE_READ_REALCREDS* ptrace access to that process.
+See the section "Ptrace access mode checking" in *ptrace*(2) for more information.
+
+== RETURN VALUE
+On success, *{command}* returns 0.
+If *{command}* fails, it will print an error and return 1.
+
+If a _command_ is being executed, the return value of *{command}* will be the return value of _command_.
+
+== NOTES
+*{command}* requires core scheduling support in the kernel.
+This can be enabled via the *CONFIG_SCHED_CORE* kernel config option.
+
+== AUTHORS
+mailto:thijs@raymakers.nl[Thijs Raymakers],
+mailto:pauld@redhat.com[Phil Auld]
+
+== COPYRIGHT
+
+Copyright {copyright} 2024 Thijs Raymakers and Phil Auld. This is free software licensed under the EUPL.
+
+== SEE ALSO
+*chrt*(1),
+*nice*(1),
+*renice*(1),
+*taskset*(1),
+*ptrace*(2),
+*sched*(7)
+
+The Linux kernel source files _Documentation/admin-guide/hw-vuln/core-scheduling.rst_
+
+include::man-common/bugreports.adoc[]
+
+include::man-common/footer.adoc[]
+
+ifdef::translation[]
+include::man-common/translation.adoc[]
+endif::[]
diff --git a/schedutils/coresched.c b/schedutils/coresched.c
new file mode 100644
index 000000000..9d8be3e12
--- /dev/null
+++ b/schedutils/coresched.c
@@ -0,0 +1,363 @@
+/**
+ * SPDX-License-Identifier: EUPL-1.2
+ *
+ * coresched.c - manage core scheduling cookies for tasks
+ *
+ * Copyright (C) 2024 Thijs Raymakers, Phil Auld
+ * Licensed under the EUPL v1.2
+ */
+
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+
+#include "c.h"
+#include "closestream.h"
+#include "nls.h"
+#include "strutils.h"
+
+// These definitions might not be defined in the header files, even if the
+// prctl interface in the kernel accepts them as valid.
+#ifndef PR_SCHED_CORE
+ #define PR_SCHED_CORE 62
+#endif
+#ifndef PR_SCHED_CORE_GET
+ #define PR_SCHED_CORE_GET 0
+#endif
+#ifndef PR_SCHED_CORE_CREATE
+ #define PR_SCHED_CORE_CREATE 1
+#endif
+#ifndef PR_SCHED_CORE_SHARE_TO
+ #define PR_SCHED_CORE_SHARE_TO 2
+#endif
+#ifndef PR_SCHED_CORE_SHARE_FROM
+ #define PR_SCHED_CORE_SHARE_FROM 3
+#endif
+#ifndef PR_SCHED_CORE_SCOPE_THREAD
+ #define PR_SCHED_CORE_SCOPE_THREAD 0
+#endif
+#ifndef PR_SCHED_CORE_SCOPE_THREAD_GROUP
+ #define PR_SCHED_CORE_SCOPE_THREAD_GROUP 1
+#endif
+#ifndef PR_SCHED_CORE_SCOPE_PROCESS_GROUP
+ #define PR_SCHED_CORE_SCOPE_PROCESS_GROUP 2
+#endif
+
+typedef int sched_core_scope;
+typedef unsigned long long sched_core_cookie;
+typedef enum {
+ SCHED_CORE_CMD_GET,
+ SCHED_CORE_CMD_NEW,
+ SCHED_CORE_CMD_COPY,
+} sched_core_cmd;
+
+struct args {
+ pid_t src;
+ pid_t dest;
+ sched_core_scope type;
+ sched_core_cmd cmd;
+ int exec_argv_offset;
+};
+
+static bool sched_core_verbose = false;
+
+static void __attribute__((__noreturn__)) usage(void)
+{
+ fputs(USAGE_HEADER, stdout);
+ fprintf(stdout, _(" %s [get] [--source <PID>]\n"),
+ program_invocation_short_name);
+ fprintf(stdout, _(" %s new [-t <TYPE>] --dest <PID>\n"),
+ program_invocation_short_name);
+ fprintf(stdout, _(" %s new [-t <TYPE>] -- PROGRAM [ARGS...]\n"),
+ program_invocation_short_name);
+ fprintf(stdout,
+ _(" %s copy [--source <PID>] [-t <TYPE>] --dest <PID>\n"),
+ program_invocation_short_name);
+ fprintf(stdout,
+ _(" %s copy [--source <PID>] [-t <TYPE>] -- PROGRAM [ARGS...]\n"),
+ program_invocation_short_name);
+
+ fputs(USAGE_SEPARATOR, stdout);
+ fputsln(_("Manage core scheduling cookies for tasks."), stdout);
+
+ fputs(USAGE_FUNCTIONS, stdout);
+ fputsln(_(" get retrieve the core scheduling cookie of a PID"),
+ stdout);
+ fputsln(_(" new assign a new core scheduling cookie to an existing\n"
+ " PID or execute a program with a new cookie"),
+ stdout);
+ fputsln(_(" copy copy the core scheduling cookie from an existing PID\n"
+ " to another PID, or execute a program with that\n"
+ " copied cookie"),
+ stdout);
+
+ fputs(USAGE_OPTIONS, stdout);
+ fprintf(stdout,
+ _(" -s, --source <PID> which PID to get the cookie from\n"
+ " If omitted, it is the PID of %s itself\n"),
+ program_invocation_short_name);
+ fputsln(_(" -d, --dest <PID> which PID to modify the cookie of\n"),
+ stdout);
+ fputsln(_(" -t, --dest-type <TYPE> type of the destination PID, or the type of the PID\n"
+ " when a new core scheduling cookie is created.\n"
+ " Can be one of the following: pid, tgid or pgid.\n"
+ " The default is tgid."),
+ stdout);
+ fputs(USAGE_SEPARATOR, stdout);
+ fputsln(_(" -v, --verbose verbose"), stdout);
+ fprintf(stdout, USAGE_HELP_OPTIONS(20));
+ fprintf(stdout, USAGE_MAN_TAIL("coresched(1)"));
+ exit(EXIT_SUCCESS);
+}
+
+#define bad_usage(FMT...) \
+ do { \
+ warnx(FMT); \
+ errtryhelp(EXIT_FAILURE); \
+ } while (0)
+
+static sched_core_cookie core_sched_get_cookie(pid_t pid)
+{
+ sched_core_cookie cookie = 0;
+ if (prctl(PR_SCHED_CORE, PR_SCHED_CORE_GET, pid,
+ PR_SCHED_CORE_SCOPE_THREAD, &cookie))
+ err(EXIT_FAILURE, _("Failed to get cookie from PID %d"), pid);
+ return cookie;
+}
+
+static void core_sched_create_cookie(pid_t pid, sched_core_scope type)
+{
+ if (prctl(PR_SCHED_CORE, PR_SCHED_CORE_CREATE, pid, type, 0))
+ err(EXIT_FAILURE, _("Failed to create cookie for PID %d"), pid);
+}
+
+static void core_sched_pull_cookie(pid_t from)
+{
+ if (prctl(PR_SCHED_CORE, PR_SCHED_CORE_SHARE_FROM, from,
+ PR_SCHED_CORE_SCOPE_THREAD, 0))
+ err(EXIT_FAILURE, _("Failed to pull cookie from PID %d"), from);
+}
+
+static void core_sched_push_cookie(pid_t to, sched_core_scope type)
+{
+ if (prctl(PR_SCHED_CORE, PR_SCHED_CORE_SHARE_TO, to, type, 0))
+ err(EXIT_FAILURE, _("Failed to push cookie to PID %d"), to);
+}
+
+static void core_sched_copy_cookie(pid_t from, pid_t to,
+ sched_core_scope to_type)
+{
+ core_sched_pull_cookie(from);
+ core_sched_push_cookie(to, to_type);
+
+ if (sched_core_verbose) {
+ sched_core_cookie before = core_sched_get_cookie(from);
+ warnx(_("copied cookie 0x%llx from PID %d to PID %d"), before,
+ from, to);
+ }
+}
+
+static void core_sched_get_and_print_cookie(pid_t pid)
+{
+ if (sched_core_verbose) {
+ sched_core_cookie after = core_sched_get_cookie(pid);
+ warnx(_("set cookie of PID %d to 0x%llx"), pid, after);
+ }
+}
+
+static void core_sched_exec_with_cookie(struct args *args, char **argv)
+{
+ // Move the argument list to the first argument of the program
+ argv = &argv[args->exec_argv_offset];
+
+ // If a source PID is provided, try to copy the cookie from
+ // that PID. Otherwise, create a brand new cookie with the
+ // provided type.
+ if (args->src) {
+ core_sched_pull_cookie(args->src);
+ core_sched_get_and_print_cookie(args->src);
+ } else {
+ pid_t pid = getpid();
+ core_sched_create_cookie(pid, args->type);
+ core_sched_get_and_print_cookie(pid);
+ }
+
+ if (execvp(argv[0], argv))
+ errexec(argv[0]);
+}
+
+// There are two failure conditions for the core scheduling prctl calls
+// that rely on the environment in which coresched is running.
+// 1. If PR_SCHED_CORE is not recognized, or not supported on this system,
+// then prctl will set errno to EINVAL. Assuming all other operands of
+// prctl are valid, we can use errno==EINVAL as a check to see whether
+// core scheduling is available on this system.
+// 2. prctl sets errno to ENODEV if SMT is not available on this system,
+// either because SMT support has been disabled in the kernel, or because
+// the hardware doesn't support it.
+static bool is_core_sched_supported(void)
+{
+ sched_core_cookie cookie = 0;
+ if (prctl(PR_SCHED_CORE, PR_SCHED_CORE_GET, getpid(),
+ PR_SCHED_CORE_SCOPE_THREAD, &cookie))
+ if (errno == EINVAL || errno == ENODEV)
+ return false;
+
+ return true;
+}
+
+static sched_core_scope parse_core_sched_type(char *str)
+{
+ if (!strcmp(str, "pid"))
+ return PR_SCHED_CORE_SCOPE_THREAD;
+ else if (!strcmp(str, "tgid"))
+ return PR_SCHED_CORE_SCOPE_THREAD_GROUP;
+ else if (!strcmp(str, "pgid"))
+ return PR_SCHED_CORE_SCOPE_PROCESS_GROUP;
+
+ bad_usage(_("'%s' is an invalid option. Must be one of pid/tgid/pgid"),
+ str);
+}
+
+static void parse_and_verify_arguments(int argc, char **argv, struct args *args)
+{
+ int c;
+
+ static const struct option longopts[] = {
+ { "source", required_argument, NULL, 's' },
+ { "dest", required_argument, NULL, 'd' },
+ { "dest-type", required_argument, NULL, 't' },
+ { "verbose", no_argument, NULL, 'v' },
+ { "version", no_argument, NULL, 'V' },
+ { "help", no_argument, NULL, 'h' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ while ((c = getopt_long(argc, argv, "s:d:t:vVh", longopts, NULL)) != -1)
+ switch (c) {
+ case 's':
+ args->src = strtopid_or_err(
+ optarg,
+ _("Failed to parse PID for -s/--source"));
+ break;
+ case 'd':
+ args->dest = strtopid_or_err(
+ optarg, _("Failed to parse PID for -d/--dest"));
+ break;
+ case 't':
+ args->type = parse_core_sched_type(optarg);
+ break;
+ case 'v':
+ sched_core_verbose = true;
+ break;
+ case 'V':
+ print_version(EXIT_SUCCESS);
+ case 'h':
+ usage();
+ default:
+ errtryhelp(EXIT_FAILURE);
+ }
+
+ if (argc <= optind) {
+ args->cmd = SCHED_CORE_CMD_GET;
+ } else {
+ if (!strcmp(argv[optind], "get"))
+ args->cmd = SCHED_CORE_CMD_GET;
+ else if (!strcmp(argv[optind], "new"))
+ args->cmd = SCHED_CORE_CMD_NEW;
+ else if (!strcmp(argv[optind], "copy"))
+ args->cmd = SCHED_CORE_CMD_COPY;
+ else
+ bad_usage(_("Unknown function"));
+
+ // Since we parsed an extra "option" outside of getopt_long, we have to
+ // increment optind manually.
+ ++optind;
+ }
+
+ if (args->cmd == SCHED_CORE_CMD_GET && args->dest)
+ bad_usage(_("get does not accept the --dest option"));
+
+ if (args->cmd == SCHED_CORE_CMD_NEW && args->src)
+ bad_usage(_("new does not accept the --source option"));
+
+ // If the -s/--source option is not specified, it defaults to the PID
+ // of the current coresched process
+ if (args->cmd != SCHED_CORE_CMD_NEW && !args->src)
+ args->src = getpid();
+
+ // More arguments have been passed, which means that the user wants to run
+ // another program with a core scheduling cookie.
+ if (argc > optind) {
+ switch (args->cmd) {
+ case SCHED_CORE_CMD_GET:
+ bad_usage(_("bad usage of the get function"));
+ break;
+ case SCHED_CORE_CMD_NEW:
+ if (args->dest)
+ bad_usage(_(
+ "new requires either a -d/--dest or a command"));
+ else
+ args->exec_argv_offset = optind;
+ break;
+ case SCHED_CORE_CMD_COPY:
+ if (args->dest)
+ bad_usage(_(
+ "copy requires either a -d/--dest or a command"));
+ else
+ args->exec_argv_offset = optind;
+ break;
+ }
+ } else {
+ if (args->cmd == SCHED_CORE_CMD_NEW && !args->dest)
+ bad_usage(_(
+ "new requires either a -d/--dest or a command"));
+ if (args->cmd == SCHED_CORE_CMD_COPY && !args->dest)
+ bad_usage(_(
+ "copy requires either a -d/--dest or a command"));
+ }
+}
+
+int main(int argc, char **argv)
+{
+ struct args args = { .type = PR_SCHED_CORE_SCOPE_THREAD_GROUP };
+
+ setlocale(LC_ALL, "");
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+ close_stdout_atexit();
+
+ parse_and_verify_arguments(argc, argv, &args);
+
+ if (!is_core_sched_supported())
+ errx(EXIT_FAILURE,
+ _("Core scheduling is not supported on this system. Either SMT "
+ "is unavailable or your kernel does not support CONFIG_SCHED_CORE."));
+
+ sched_core_cookie cookie;
+
+ switch (args.cmd) {
+ case SCHED_CORE_CMD_GET:
+ cookie = core_sched_get_cookie(args.src);
+ printf(_("cookie of pid %d is 0x%llx\n"), args.src, cookie);
+ break;
+ case SCHED_CORE_CMD_NEW:
+ if (args.exec_argv_offset) {
+ core_sched_exec_with_cookie(&args, argv);
+ } else {
+ core_sched_create_cookie(args.dest, args.type);
+ core_sched_get_and_print_cookie(args.dest);
+ }
+ break;
+ case SCHED_CORE_CMD_COPY:
+ if (args.exec_argv_offset)
+ core_sched_exec_with_cookie(&args, argv);
+ else
+ core_sched_copy_cookie(args.src, args.dest, args.type);
+ break;
+ default:
+ usage();
+ }
+}
diff --git a/tests/commands.sh b/tests/commands.sh
index 5674c5ff0..9eef92ccb 100644
--- a/tests/commands.sh
+++ b/tests/commands.sh
@@ -71,6 +71,7 @@ TS_CMD_COLCRT=${TS_CMD_COLCRT:-"${ts_commandsdir}colcrt"}
TS_CMD_COLRM=${TS_CMD_COLRM:-"${ts_commandsdir}colrm"}
TS_CMD_COL=${TS_CMD_COL:-"${ts_commandsdir}col"}
TS_CMD_COLUMN=${TS_CMD_COLUMN:-"${ts_commandsdir}column"}
+TS_CMD_CORESCHED=${TS_CMD_CORESCHED:-"${ts_commandsdir}coresched"}
TS_CMD_ENOSYS=${TS_CMD_ENOSYS-"${ts_commandsdir}enosys"}
TS_CMD_EJECT=${TS_CMD_EJECT-"${ts_commandsdir}eject"}
TS_CMD_EXCH=${TS_CMD_EXCH-"${ts_commandsdir}exch"}
diff --git a/tests/expected/schedutils/coresched-copy-from-child-to-parent b/tests/expected/schedutils/coresched-copy-from-child-to-parent
new file mode 100644
index 000000000..5b9c40052
--- /dev/null
+++ b/tests/expected/schedutils/coresched-copy-from-child-to-parent
@@ -0,0 +1 @@
+DIFFERENT_COOKIE
diff --git a/tests/expected/schedutils/coresched-copy-from-parent-to-nested-child b/tests/expected/schedutils/coresched-copy-from-parent-to-nested-child
new file mode 100644
index 000000000..ecfc41142
--- /dev/null
+++ b/tests/expected/schedutils/coresched-copy-from-parent-to-nested-child
@@ -0,0 +1 @@
+SAME_COOKIE
diff --git a/tests/expected/schedutils/coresched-get-cookie-own-pid b/tests/expected/schedutils/coresched-get-cookie-own-pid
new file mode 100644
index 000000000..84f182cbe
--- /dev/null
+++ b/tests/expected/schedutils/coresched-get-cookie-own-pid
@@ -0,0 +1 @@
+cookie of pid OWN_PID is PARENT_COOKIE
diff --git a/tests/expected/schedutils/coresched-get-cookie-parent-pid b/tests/expected/schedutils/coresched-get-cookie-parent-pid
new file mode 100644
index 000000000..e183e0402
--- /dev/null
+++ b/tests/expected/schedutils/coresched-get-cookie-parent-pid
@@ -0,0 +1 @@
+cookie of pid PARENT_PID is PARENT_COOKIE
diff --git a/tests/expected/schedutils/coresched-new-child-with-new-cookie b/tests/expected/schedutils/coresched-new-child-with-new-cookie
new file mode 100644
index 000000000..5b9c40052
--- /dev/null
+++ b/tests/expected/schedutils/coresched-new-child-with-new-cookie
@@ -0,0 +1 @@
+DIFFERENT_COOKIE
diff --git a/tests/expected/schedutils/coresched-set-cookie-parent-pid.err b/tests/expected/schedutils/coresched-set-cookie-parent-pid.err
new file mode 100644
index 000000000..e7318ffc2
--- /dev/null
+++ b/tests/expected/schedutils/coresched-set-cookie-parent-pid.err
@@ -0,0 +1 @@
+coresched: set cookie of PID PARENT_PID to PARENT_COOKIE
diff --git a/tests/expected/schedutils/set-cookie-parent-pid b/tests/expected/schedutils/set-cookie-parent-pid
new file mode 100644
index 000000000..e7318ffc2
--- /dev/null
+++ b/tests/expected/schedutils/set-cookie-parent-pid
@@ -0,0 +1 @@
+coresched: set cookie of PID PARENT_PID to PARENT_COOKIE
diff --git a/tests/ts/schedutils/coresched b/tests/ts/schedutils/coresched
new file mode 100755
index 000000000..2ab0803bd
--- /dev/null
+++ b/tests/ts/schedutils/coresched
@@ -0,0 +1,83 @@
+#!/bin/bash
+# SPDX-License-Identifier: EUPL-1.2
+#
+# This file is part of util-linux
+#
+# Copyright (C) 2024 Thijs Raymakers
+# Licensed under the EUPL v1.2
+
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="coresched"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+ts_check_test_command "$TS_CMD_CORESCHED"
+ts_check_prog "tee"
+ts_check_prog "sed"
+
+# If coresched cannot succesfully run, skip the test suite
+CORESCHED_TEST_KERNEL_SUPPORT_CMD=$($TS_CMD_CORESCHED 2>&1)
+if [[ $CORESCHED_TEST_KERNEL_SUPPORT_CMD == *"CONFIG_SCHED_CORE"* ]]; then
+ ts_skip "Kernel has no CONFIG_SCHED_CORE support or SMT is not available"
+fi
+
+# The output of coresched contains PIDs and core scheduling cookies, both of which should be
+# assumed to be random values as we have no control over them. The tests replace these values
+# with sed before writing them to the output file, so it can match the expected output file.
+# - The PID of this bash script is replaced with the placeholder `OWN_PID`
+# - The core scheduling cookie of this bash script is replaced by `COOKIE`
+# - Any other cookie is replaced by `DIFFERENT_COOKIE`
+# The behavior of coresched does not depend on the exact values of these cookies, so using
+# placeholder values does not change the behavior tests.
+ts_init_subtest "set-cookie-parent-pid"
+CORESCHED_OUTPUT=$( ($TS_CMD_CORESCHED -v new -d $$ \
+ | tee -a "$TS_OUTPUT") 3>&1 1>&2 2>&3 \
+ | sed "s/$$/PARENT_PID/g")
+CORESCHED_PARENT_COOKIE=$(echo "$CORESCHED_OUTPUT" | sed 's/^.*\(0x.*$\)/\1/g')
+if [ -z "$CORESCHED_PARENT_COOKIE" ]; then
+ ts_failed "empty value for CORESCHED_PARENT_COOKIE"
+fi
+CORESCHED_OUTPUT=$(echo "$CORESCHED_OUTPUT" \
+ | sed "s/$CORESCHED_PARENT_COOKIE/PARENT_COOKIE/g")
+echo "$CORESCHED_OUTPUT" >> "$TS_ERRLOG"
+ts_finalize_subtest
+
+ts_init_subtest "get-cookie-parent-pid"
+$TS_CMD_CORESCHED get -s $$ 2>> "$TS_ERRLOG" \
+ | sed -e "s/$$/PARENT_PID/g" \
+ -e "s/$CORESCHED_PARENT_COOKIE/PARENT_COOKIE/g" >> "$TS_OUTPUT"
+ts_finalize_subtest
+
+ts_init_subtest "get-cookie-own-pid"
+$TS_CMD_CORESCHED get 2>> "$TS_ERRLOG" \
+ | sed -e "s/pid [0-9]\+/pid OWN_PID/g" \
+ -e "s/$CORESCHED_PARENT_COOKIE/PARENT_COOKIE/g" >> "$TS_OUTPUT"
+ts_finalize_subtest
+
+ts_init_subtest "new-child-with-new-cookie"
+$TS_CMD_CORESCHED new -- "$TS_CMD_CORESCHED" get 2>> "$TS_ERRLOG" \
+ | sed -e 's/^.*\(0x.*$\)/\1/g' \
+ -e "s/$CORESCHED_PARENT_COOKIE/SAME_COOKIE/g" \
+ -e "s/0x.*$/DIFFERENT_COOKIE/g" >> "$TS_OUTPUT"
+ts_finalize_subtest
+
+ts_init_subtest "copy-from-parent-to-nested-child"
+$TS_CMD_CORESCHED new -- /bin/bash -c \
+ "$TS_CMD_CORESCHED copy -s $$ -- $TS_CMD_CORESCHED get" \
+2>> "$TS_ERRLOG" \
+ | sed -e 's/^.*\(0x.*$\)/\1/g' \
+ -e "s/$CORESCHED_PARENT_COOKIE/SAME_COOKIE/g" \
+ -e "s/0x.*$/DIFFERENT_COOKIE/g" >> "$TS_OUTPUT"
+ts_finalize_subtest
+
+ts_init_subtest "copy-from-child-to-parent"
+$TS_CMD_CORESCHED new -- /bin/bash -c \
+ "$TS_CMD_CORESCHED copy -s \$\$ -d $$"
+$TS_CMD_CORESCHED get 2>> "$TS_ERRLOG" \
+ | sed -e 's/^.*\(0x.*$\)/\1/g' \
+ -e "s/$CORESCHED_PARENT_COOKIE/SAME_COOKIE/g" \
+ -e "s/0x.*$/DIFFERENT_COOKIE/g" >> "$TS_OUTPUT"
+ts_finalize_subtest
+
+ts_finalize
--
2.44.0
^ permalink raw reply related
* Re: [PATCH v11] coresched: Manage core scheduling cookies for tasks
From: Thomas Weißschuh @ 2024-04-25 15:51 UTC (permalink / raw)
To: Thijs Raymakers; +Cc: kzak, util-linux, Phil Auld
In-Reply-To: <20240425153627.120762-1-thijs@raymakers.nl>
Hi,
On 2024-04-25 17:36:26+0000, Thijs Raymakers wrote:
> Co-authored-by: Phil Auld <pauld@redhat.com>
> Signed-off-by: Phil Auld <pauld@redhat.com>
> Signed-off-by: Thijs Raymakers <thijs@raymakers.nl>
> ---
>
> I noticed that the CI pipeline failed because the coresched test reported
> a "No such device" error.
>
> https://download.copr.fedorainfracloud.org/results/packit/util-linux-util-linux-2990/fedora-rawhide-x86_64/07343926-util-linux/builder-live.log.gz
>
> This happens because the following check in the kernel's
> kernel/sched/core_sched.c fails:
>
> > /* Called from prctl interface: PR_SCHED_CORE */
> > int sched_core_share_pid(unsigned int cmd, pid_t pid, enum pid_type type,
> > unsigned long uaddr)
> > {
> > [snip]
> >
> > if (!static_branch_likely(&sched_smt_present))
> > return -ENODEV;
>
> The prctl call will return ENODEV whenever SMT is not available,
> but the kernel is compiled with CONFIG_SCHED_CORE. I've added a check that skips
> the tests for coresched when this is the case.
>
> Thijs
>
>
> Interdiff against v10:
> diff --git a/schedutils/coresched.c b/schedutils/coresched.c
> index 7bc5c9d38..beeb01702 100644
> --- a/schedutils/coresched.c
> +++ b/schedutils/coresched.c
> @@ -328,7 +328,7 @@ int main(int argc, char **argv)
>
> if (!is_core_sched_supported())
> errx(EXIT_FAILURE,
> - _("No support for core scheduling found. Does your kernel"
> + _("No support for core scheduling found. Does your kernel "
> "support CONFIG_SCHED_CORE?"));
>
> sched_core_cookie cookie;
> diff --git a/tests/ts/schedutils/coresched b/tests/ts/schedutils/coresched
> index e34fa319f..debb8cbfc 100755
> --- a/tests/ts/schedutils/coresched
> +++ b/tests/ts/schedutils/coresched
> @@ -22,6 +22,12 @@ if [[ $CORESCHED_TEST_KERNEL_SUPPORT_CMD == *"CONFIG_SCHED_CORE"* ]]; then
> ts_skip "Kernel has no CONFIG_SCHED_CORE support"
> fi
>
> +# Kernel and the machine must support SMT
> +CORESCHED_HAS_SMT_SUPPORT=$(</sys/devices/system/cpu/smt/control)
> +if [[ "$CORESCHED_HAS_SMT_SUPPORT" != "on" ]]; then
> + ts_skip "SMT is unavailable (state: $CORESCHED_HAS_SMT_SUPPORT)"
> +fi
> +
> # The output of coresched contains PIDs and core scheduling cookies, both of which should be
> # assumed to be random values as we have no control over them. The tests replace these values
> # with sed before writing them to the output file, so it can match the expected output file.
>
> .gitignore | 1 +
> bash-completion/coresched | 0
> configure.ac | 12 +-
> meson.build | 16 +-
> meson_options.txt | 2 +-
> schedutils/Makemodule.am | 8 +
> schedutils/coresched.1.adoc | 139 +++++++
> schedutils/coresched.c | 358 ++++++++++++++++++
> tests/commands.sh | 1 +
> .../coresched-copy-from-child-to-parent | 1 +
> ...coresched-copy-from-parent-to-nested-child | 1 +
> .../schedutils/coresched-get-cookie-own-pid | 1 +
> .../coresched-get-cookie-parent-pid | 1 +
> .../coresched-new-child-with-new-cookie | 1 +
> .../coresched-set-cookie-parent-pid.err | 1 +
> .../expected/schedutils/set-cookie-parent-pid | 1 +
> tests/ts/schedutils/coresched | 89 +++++
> 17 files changed, 627 insertions(+), 6 deletions(-)
> create mode 100644 bash-completion/coresched
> create mode 100644 schedutils/coresched.1.adoc
> create mode 100644 schedutils/coresched.c
> create mode 100644 tests/expected/schedutils/coresched-copy-from-child-to-parent
> create mode 100644 tests/expected/schedutils/coresched-copy-from-parent-to-nested-child
> create mode 100644 tests/expected/schedutils/coresched-get-cookie-own-pid
> create mode 100644 tests/expected/schedutils/coresched-get-cookie-parent-pid
> create mode 100644 tests/expected/schedutils/coresched-new-child-with-new-cookie
> create mode 100644 tests/expected/schedutils/coresched-set-cookie-parent-pid.err
> create mode 100644 tests/expected/schedutils/set-cookie-parent-pid
> create mode 100755 tests/ts/schedutils/coresched
[..]
> +// If PR_SCHED_CORE is not recognized, or not supported on this system,
> +// then prctl will set errno to EINVAL. Assuming all other operands of
> +// prctl are valid, we can use errno==EINVAL as a check to see whether
> +// core scheduling is available on this system.
> +static bool is_core_sched_supported(void)
> +{
> + sched_core_cookie cookie = 0;
> + if (prctl(PR_SCHED_CORE, PR_SCHED_CORE_GET, getpid(),
> + PR_SCHED_CORE_SCOPE_THREAD, &cookie))
> + if (errno == EINVAL)
> + return false;
IMO the ENODEV should be handled here.
So the user can get a proper error message.
This would then also remove the need for another ts_skip in the
testcase.
> +
> + return true;
> +}
> +
[..]
^ permalink raw reply
* [PATCH v11] coresched: Manage core scheduling cookies for tasks
From: Thijs Raymakers @ 2024-04-25 15:36 UTC (permalink / raw)
To: thomas; +Cc: kzak, util-linux, Thijs Raymakers, Phil Auld
In-Reply-To: <20240423111251.367023-1-thijs@raymakers.nl>
Co-authored-by: Phil Auld <pauld@redhat.com>
Signed-off-by: Phil Auld <pauld@redhat.com>
Signed-off-by: Thijs Raymakers <thijs@raymakers.nl>
---
I noticed that the CI pipeline failed because the coresched test reported
a "No such device" error.
https://download.copr.fedorainfracloud.org/results/packit/util-linux-util-linux-2990/fedora-rawhide-x86_64/07343926-util-linux/builder-live.log.gz
This happens because the following check in the kernel's
kernel/sched/core_sched.c fails:
> /* Called from prctl interface: PR_SCHED_CORE */
> int sched_core_share_pid(unsigned int cmd, pid_t pid, enum pid_type type,
> unsigned long uaddr)
> {
> [snip]
>
> if (!static_branch_likely(&sched_smt_present))
> return -ENODEV;
The prctl call will return ENODEV whenever SMT is not available,
but the kernel is compiled with CONFIG_SCHED_CORE. I've added a check that skips
the tests for coresched when this is the case.
Thijs
Interdiff against v10:
diff --git a/schedutils/coresched.c b/schedutils/coresched.c
index 7bc5c9d38..beeb01702 100644
--- a/schedutils/coresched.c
+++ b/schedutils/coresched.c
@@ -328,7 +328,7 @@ int main(int argc, char **argv)
if (!is_core_sched_supported())
errx(EXIT_FAILURE,
- _("No support for core scheduling found. Does your kernel"
+ _("No support for core scheduling found. Does your kernel "
"support CONFIG_SCHED_CORE?"));
sched_core_cookie cookie;
diff --git a/tests/ts/schedutils/coresched b/tests/ts/schedutils/coresched
index e34fa319f..debb8cbfc 100755
--- a/tests/ts/schedutils/coresched
+++ b/tests/ts/schedutils/coresched
@@ -22,6 +22,12 @@ if [[ $CORESCHED_TEST_KERNEL_SUPPORT_CMD == *"CONFIG_SCHED_CORE"* ]]; then
ts_skip "Kernel has no CONFIG_SCHED_CORE support"
fi
+# Kernel and the machine must support SMT
+CORESCHED_HAS_SMT_SUPPORT=$(</sys/devices/system/cpu/smt/control)
+if [[ "$CORESCHED_HAS_SMT_SUPPORT" != "on" ]]; then
+ ts_skip "SMT is unavailable (state: $CORESCHED_HAS_SMT_SUPPORT)"
+fi
+
# The output of coresched contains PIDs and core scheduling cookies, both of which should be
# assumed to be random values as we have no control over them. The tests replace these values
# with sed before writing them to the output file, so it can match the expected output file.
.gitignore | 1 +
bash-completion/coresched | 0
configure.ac | 12 +-
meson.build | 16 +-
meson_options.txt | 2 +-
schedutils/Makemodule.am | 8 +
schedutils/coresched.1.adoc | 139 +++++++
schedutils/coresched.c | 358 ++++++++++++++++++
tests/commands.sh | 1 +
.../coresched-copy-from-child-to-parent | 1 +
...coresched-copy-from-parent-to-nested-child | 1 +
.../schedutils/coresched-get-cookie-own-pid | 1 +
.../coresched-get-cookie-parent-pid | 1 +
.../coresched-new-child-with-new-cookie | 1 +
.../coresched-set-cookie-parent-pid.err | 1 +
.../expected/schedutils/set-cookie-parent-pid | 1 +
tests/ts/schedutils/coresched | 89 +++++
17 files changed, 627 insertions(+), 6 deletions(-)
create mode 100644 bash-completion/coresched
create mode 100644 schedutils/coresched.1.adoc
create mode 100644 schedutils/coresched.c
create mode 100644 tests/expected/schedutils/coresched-copy-from-child-to-parent
create mode 100644 tests/expected/schedutils/coresched-copy-from-parent-to-nested-child
create mode 100644 tests/expected/schedutils/coresched-get-cookie-own-pid
create mode 100644 tests/expected/schedutils/coresched-get-cookie-parent-pid
create mode 100644 tests/expected/schedutils/coresched-new-child-with-new-cookie
create mode 100644 tests/expected/schedutils/coresched-set-cookie-parent-pid.err
create mode 100644 tests/expected/schedutils/set-cookie-parent-pid
create mode 100755 tests/ts/schedutils/coresched
diff --git a/.gitignore b/.gitignore
index 6ecbfa7fe..316f3cdcc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -94,6 +94,7 @@ ylwrap
/colcrt
/colrm
/column
+/coresched
/ctrlaltdel
/delpart
/dmesg
diff --git a/bash-completion/coresched b/bash-completion/coresched
new file mode 100644
index 000000000..e69de29bb
diff --git a/configure.ac b/configure.ac
index 1d7a9cf70..70a60cf5d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2514,9 +2514,9 @@ UL_REQUIRES_HAVE([setterm], [ncursesw, ncurses], [ncursesw or ncurses library])
AM_CONDITIONAL([BUILD_SETTERM], [test "x$build_setterm" = xyes])
# build_schedutils= is just configure-only variable to control
-# ionice, taskset and chrt
+# ionice, taskset, coresched and chrt
AC_ARG_ENABLE([schedutils],
- AS_HELP_STRING([--disable-schedutils], [do not build chrt, ionice, taskset]),
+ AS_HELP_STRING([--disable-schedutils], [do not build chrt, ionice, taskset, coresched]),
[], [UL_DEFAULT_ENABLE([schedutils], [check])]
)
@@ -2559,6 +2559,14 @@ UL_REQUIRES_SYSCALL_CHECK([taskset],
AM_CONDITIONAL([BUILD_TASKSET], [test "x$build_taskset" = xyes])
+UL_ENABLE_ALIAS([coresched], [schedutils])
+UL_BUILD_INIT([coresched])
+UL_REQUIRES_SYSCALL_CHECK([coresched],
+ [UL_CHECK_SYSCALL([prctl])],
+ [prctl])
+AM_CONDITIONAL([BUILD_CORESCHED], [test "x$build_coresched" = xyes])
+
+
have_schedsetter=no
AS_IF([test "x$ac_cv_func_sched_setscheduler" = xyes], [have_schedsetter=yes],
[test "x$ac_cv_func_sched_setattr" = xyes], [have_schedsetter=yes])
diff --git a/meson.build b/meson.build
index 5b4f59b8c..3cfd63449 100644
--- a/meson.build
+++ b/meson.build
@@ -3194,13 +3194,23 @@ exe4 = executable(
install : opt,
build_by_default : opt)
+exe5 = executable(
+ 'coresched',
+ 'schedutils/coresched.c',
+ include_directories : includes,
+ link_with : lib_common,
+ install_dir : usrbin_exec_dir,
+ install : opt,
+ build_by_default : opt)
+
if opt and not is_disabler(exe)
- exes += [exe, exe2, exe3, exe4]
+ exes += [exe, exe2, exe3, exe4, exe5]
manadocs += ['schedutils/chrt.1.adoc',
'schedutils/ionice.1.adoc',
'schedutils/taskset.1.adoc',
- 'schedutils/uclampset.1.adoc']
- bashcompletions += ['chrt', 'ionice', 'taskset', 'uclampset']
+ 'schedutils/uclampset.1.adoc',
+ 'schedutils/coresched.1.adoc']
+ bashcompletions += ['chrt', 'ionice', 'taskset', 'uclampset', 'coresched']
endif
############################################################
diff --git a/meson_options.txt b/meson_options.txt
index ca76530a9..8a70555d7 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -182,7 +182,7 @@ option('build-pipesz', type : 'feature',
option('build-setterm', type : 'feature',
description : 'build setterm')
option('build-schedutils', type : 'feature',
- description : 'build chrt, ionice, taskset')
+ description : 'build chrt, ionice, taskset, coresched')
option('build-wall', type : 'feature',
description : 'build wall')
option('build-write', type : 'feature',
diff --git a/schedutils/Makemodule.am b/schedutils/Makemodule.am
index 1040da85f..0cb655401 100644
--- a/schedutils/Makemodule.am
+++ b/schedutils/Makemodule.am
@@ -29,3 +29,11 @@ dist_noinst_DATA += schedutils/uclampset.1.adoc
uclampset_SOURCES = schedutils/uclampset.c schedutils/sched_attr.h
uclampset_LDADD = $(LDADD) libcommon.la
endif
+
+if BUILD_CORESCHED
+usrbin_exec_PROGRAMS += coresched
+MANPAGES += schedutils/coresched.1
+dist_noinst_DATA += schedutils/coresched.1.adoc
+coresched_SOURCES = schedutils/coresched.c
+coresched_LDADD = $(LDADD) libcommon.la
+endif
diff --git a/schedutils/coresched.1.adoc b/schedutils/coresched.1.adoc
new file mode 100644
index 000000000..8a9c28846
--- /dev/null
+++ b/schedutils/coresched.1.adoc
@@ -0,0 +1,139 @@
+//po4a: entry man manual
+////
+coresched(1) manpage
+////
+= coresched(1)
+:doctype: manpage
+:man manual: User Commands
+:man source: util-linux {release-version}
+:page-layout: base
+:command: coresched
+:colon: :
+:copyright: ©
+
+== NAME
+
+coresched - manage core scheduling cookies for tasks
+
+== SYNOPSIS
+
+*{command}* [*get*] [*-s* _pid_]
+
+*{command}* *new* [*-t* _type_] *-d* _pid_
+
+*{command}* *new* [*-t* _type_] \-- _command_ [_argument_...]
+
+*{command}* *copy* [*-s* _pid_] [*-t* _type_] *-d* _pid_
+
+*{command}* *copy* [*-s* _pid_] [*-t* _type_] \-- _command_ [_argument_...]
+
+== DESCRIPTION
+The *{command}* command is used to retrieve or modify the core scheduling cookies of a running process given its _pid_, or to spawn a new _command_ with core scheduling cookies.
+
+Core scheduling permits the definition of groups of tasks that are allowed to share a physical core.
+This is done by assigning a cookie to each task.
+Only tasks have the same cookie are allowed to be scheduled on the same physical core.
+
+It is possible to either assign a new random cookie to a task, or copy a cookie from another task. It is not possible to choose the value of the cookie.
+
+== FUNCTIONS
+*get*::
+Retrieve the core scheduling cookie of the PID specified in *-s*.
+If *-s* is omitted, it will get the cookie of the current *{command}* process.
+
+*new*::
+Assign a new cookie to an existing PID specified in *-d*, or execute _command_ with a new cookie.
+
+*copy*::
+Copy the cookie from an existing PID (*-s*) to another PID (*-d*), or execute _command_ with that cookie.
+If *-s* is omitted, it will get the cookie of the current *{command}* process.
+
+If no function is specified, it will run the *get* function.
+
+== OPTIONS
+*-s*, *--source* _PID_::
+Which _PID_ to get the cookie from.
+If this option is omitted, it will get the cookie from the current *{command}* process.
+
+*-d*, *--dest* _PID_::
+Which _PID_ to modify the cookie of.
+
+*-t*, *--dest-type* _TYPE_::
+The type of the PID whose cookie will be modified. This can be one of three values:
+- *pid*, or process ID
+- *tgid*, or thread group ID (default value)
+- *pgid*, or process group ID
+
+*-v*, *--verbose*::
+Show extra information when modifying cookies of tasks.
+
+*-h*, *--help*::
+Display help text and exit.
+
+*-V*, *--version*::
+Print version and exit.
+
+== EXAMPLES
+Get the core scheduling cookie of the {command} task itself, usually inherited from its parent{colon}::
+*{command} get*
+
+Get the core scheduling cookie of a task with PID _123_{colon}::
+*{command} get -s* _123_
+
+Give a task with PID _123_ a new core scheduling cookie{colon}::
+*{command} new -d* _123_
+
+Spawn a new task with a new core scheduling cookie{colon}::
+*{command} new* \-- _command_ [_argument_...]
+
+Copy the cookie from the current {command} process another task with pid _456_{colon}::
+*{command} copy -d* _456_
+
+Copy the cookie from a task with pid _123_ to another task with pid _456_{colon}::
+*{command} copy -s* _123_ *-d* _456_
+
+Copy the cookie from a task with pid _123_ to a new task _command_{colon}::
+*{command} copy -s* _123_ \-- _command_ [_argument_...]
+
+Copy the cookie from a task with pid _123_ to the process group ID _456_{colon}::
+*{command} copy -s* _123_ *-t* _pgid_ *-d* _456_
+
+== PERMISSIONS
+Retrieving or modifying the core scheduling cookie of a process requires *PTRACE_MODE_READ_REALCREDS* ptrace access to that process.
+See the section "Ptrace access mode checking" in *ptrace*(2) for more information.
+
+== RETURN VALUE
+On success, *{command}* returns 0.
+If *{command}* fails, it will print an error and return 1.
+
+If a _command_ is being executed, the return value of *{command}* will be the return value of _command_.
+
+== NOTES
+*{command}* requires core scheduling support in the kernel.
+This can be enabled via the *CONFIG_SCHED_CORE* kernel config option.
+
+== AUTHORS
+mailto:thijs@raymakers.nl[Thijs Raymakers],
+mailto:pauld@redhat.com[Phil Auld]
+
+== COPYRIGHT
+
+Copyright {copyright} 2024 Thijs Raymakers and Phil Auld. This is free software licensed under the EUPL.
+
+== SEE ALSO
+*chrt*(1),
+*nice*(1),
+*renice*(1),
+*taskset*(1),
+*ptrace*(2),
+*sched*(7)
+
+The Linux kernel source files _Documentation/admin-guide/hw-vuln/core-scheduling.rst_
+
+include::man-common/bugreports.adoc[]
+
+include::man-common/footer.adoc[]
+
+ifdef::translation[]
+include::man-common/translation.adoc[]
+endif::[]
diff --git a/schedutils/coresched.c b/schedutils/coresched.c
new file mode 100644
index 000000000..beeb01702
--- /dev/null
+++ b/schedutils/coresched.c
@@ -0,0 +1,358 @@
+/**
+ * SPDX-License-Identifier: EUPL-1.2
+ *
+ * coresched.c - manage core scheduling cookies for tasks
+ *
+ * Copyright (C) 2024 Thijs Raymakers, Phil Auld
+ * Licensed under the EUPL v1.2
+ */
+
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+
+#include "c.h"
+#include "closestream.h"
+#include "nls.h"
+#include "strutils.h"
+
+// These definitions might not be defined in the header files, even if the
+// prctl interface in the kernel accepts them as valid.
+#ifndef PR_SCHED_CORE
+ #define PR_SCHED_CORE 62
+#endif
+#ifndef PR_SCHED_CORE_GET
+ #define PR_SCHED_CORE_GET 0
+#endif
+#ifndef PR_SCHED_CORE_CREATE
+ #define PR_SCHED_CORE_CREATE 1
+#endif
+#ifndef PR_SCHED_CORE_SHARE_TO
+ #define PR_SCHED_CORE_SHARE_TO 2
+#endif
+#ifndef PR_SCHED_CORE_SHARE_FROM
+ #define PR_SCHED_CORE_SHARE_FROM 3
+#endif
+#ifndef PR_SCHED_CORE_SCOPE_THREAD
+ #define PR_SCHED_CORE_SCOPE_THREAD 0
+#endif
+#ifndef PR_SCHED_CORE_SCOPE_THREAD_GROUP
+ #define PR_SCHED_CORE_SCOPE_THREAD_GROUP 1
+#endif
+#ifndef PR_SCHED_CORE_SCOPE_PROCESS_GROUP
+ #define PR_SCHED_CORE_SCOPE_PROCESS_GROUP 2
+#endif
+
+typedef int sched_core_scope;
+typedef unsigned long long sched_core_cookie;
+typedef enum {
+ SCHED_CORE_CMD_GET,
+ SCHED_CORE_CMD_NEW,
+ SCHED_CORE_CMD_COPY,
+} sched_core_cmd;
+
+struct args {
+ pid_t src;
+ pid_t dest;
+ sched_core_scope type;
+ sched_core_cmd cmd;
+ int exec_argv_offset;
+};
+
+static bool sched_core_verbose = false;
+
+static void __attribute__((__noreturn__)) usage(void)
+{
+ fputs(USAGE_HEADER, stdout);
+ fprintf(stdout, _(" %s [get] [--source <PID>]\n"),
+ program_invocation_short_name);
+ fprintf(stdout, _(" %s new [-t <TYPE>] --dest <PID>\n"),
+ program_invocation_short_name);
+ fprintf(stdout, _(" %s new [-t <TYPE>] -- PROGRAM [ARGS...]\n"),
+ program_invocation_short_name);
+ fprintf(stdout,
+ _(" %s copy [--source <PID>] [-t <TYPE>] --dest <PID>\n"),
+ program_invocation_short_name);
+ fprintf(stdout,
+ _(" %s copy [--source <PID>] [-t <TYPE>] -- PROGRAM [ARGS...]\n"),
+ program_invocation_short_name);
+
+ fputs(USAGE_SEPARATOR, stdout);
+ fputsln(_("Manage core scheduling cookies for tasks."), stdout);
+
+ fputs(USAGE_FUNCTIONS, stdout);
+ fputsln(_(" get retrieve the core scheduling cookie of a PID"),
+ stdout);
+ fputsln(_(" new assign a new core scheduling cookie to an existing\n"
+ " PID or execute a program with a new cookie"),
+ stdout);
+ fputsln(_(" copy copy the core scheduling cookie from an existing PID\n"
+ " to another PID, or execute a program with that\n"
+ " copied cookie"),
+ stdout);
+
+ fputs(USAGE_OPTIONS, stdout);
+ fprintf(stdout,
+ _(" -s, --source <PID> which PID to get the cookie from\n"
+ " If omitted, it is the PID of %s itself\n"),
+ program_invocation_short_name);
+ fputsln(_(" -d, --dest <PID> which PID to modify the cookie of\n"),
+ stdout);
+ fputsln(_(" -t, --dest-type <TYPE> type of the destination PID, or the type of the PID\n"
+ " when a new core scheduling cookie is created.\n"
+ " Can be one of the following: pid, tgid or pgid.\n"
+ " The default is tgid."),
+ stdout);
+ fputs(USAGE_SEPARATOR, stdout);
+ fputsln(_(" -v, --verbose verbose"), stdout);
+ fprintf(stdout, USAGE_HELP_OPTIONS(20));
+ fprintf(stdout, USAGE_MAN_TAIL("coresched(1)"));
+ exit(EXIT_SUCCESS);
+}
+
+#define bad_usage(FMT...) \
+ do { \
+ warnx(FMT); \
+ errtryhelp(EXIT_FAILURE); \
+ } while (0)
+
+static sched_core_cookie core_sched_get_cookie(pid_t pid)
+{
+ sched_core_cookie cookie = 0;
+ if (prctl(PR_SCHED_CORE, PR_SCHED_CORE_GET, pid,
+ PR_SCHED_CORE_SCOPE_THREAD, &cookie))
+ err(EXIT_FAILURE, _("Failed to get cookie from PID %d"), pid);
+ return cookie;
+}
+
+static void core_sched_create_cookie(pid_t pid, sched_core_scope type)
+{
+ if (prctl(PR_SCHED_CORE, PR_SCHED_CORE_CREATE, pid, type, 0))
+ err(EXIT_FAILURE, _("Failed to create cookie for PID %d"), pid);
+}
+
+static void core_sched_pull_cookie(pid_t from)
+{
+ if (prctl(PR_SCHED_CORE, PR_SCHED_CORE_SHARE_FROM, from,
+ PR_SCHED_CORE_SCOPE_THREAD, 0))
+ err(EXIT_FAILURE, _("Failed to pull cookie from PID %d"), from);
+}
+
+static void core_sched_push_cookie(pid_t to, sched_core_scope type)
+{
+ if (prctl(PR_SCHED_CORE, PR_SCHED_CORE_SHARE_TO, to, type, 0))
+ err(EXIT_FAILURE, _("Failed to push cookie to PID %d"), to);
+}
+
+static void core_sched_copy_cookie(pid_t from, pid_t to,
+ sched_core_scope to_type)
+{
+ core_sched_pull_cookie(from);
+ core_sched_push_cookie(to, to_type);
+
+ if (sched_core_verbose) {
+ sched_core_cookie before = core_sched_get_cookie(from);
+ warnx(_("copied cookie 0x%llx from PID %d to PID %d"), before,
+ from, to);
+ }
+}
+
+static void core_sched_get_and_print_cookie(pid_t pid)
+{
+ if (sched_core_verbose) {
+ sched_core_cookie after = core_sched_get_cookie(pid);
+ warnx(_("set cookie of PID %d to 0x%llx"), pid, after);
+ }
+}
+
+static void core_sched_exec_with_cookie(struct args *args, char **argv)
+{
+ // Move the argument list to the first argument of the program
+ argv = &argv[args->exec_argv_offset];
+
+ // If a source PID is provided, try to copy the cookie from
+ // that PID. Otherwise, create a brand new cookie with the
+ // provided type.
+ if (args->src) {
+ core_sched_pull_cookie(args->src);
+ core_sched_get_and_print_cookie(args->src);
+ } else {
+ pid_t pid = getpid();
+ core_sched_create_cookie(pid, args->type);
+ core_sched_get_and_print_cookie(pid);
+ }
+
+ if (execvp(argv[0], argv))
+ errexec(argv[0]);
+}
+
+// If PR_SCHED_CORE is not recognized, or not supported on this system,
+// then prctl will set errno to EINVAL. Assuming all other operands of
+// prctl are valid, we can use errno==EINVAL as a check to see whether
+// core scheduling is available on this system.
+static bool is_core_sched_supported(void)
+{
+ sched_core_cookie cookie = 0;
+ if (prctl(PR_SCHED_CORE, PR_SCHED_CORE_GET, getpid(),
+ PR_SCHED_CORE_SCOPE_THREAD, &cookie))
+ if (errno == EINVAL)
+ return false;
+
+ return true;
+}
+
+static sched_core_scope parse_core_sched_type(char *str)
+{
+ if (!strcmp(str, "pid"))
+ return PR_SCHED_CORE_SCOPE_THREAD;
+ else if (!strcmp(str, "tgid"))
+ return PR_SCHED_CORE_SCOPE_THREAD_GROUP;
+ else if (!strcmp(str, "pgid"))
+ return PR_SCHED_CORE_SCOPE_PROCESS_GROUP;
+
+ bad_usage(_("'%s' is an invalid option. Must be one of pid/tgid/pgid"),
+ str);
+}
+
+static void parse_and_verify_arguments(int argc, char **argv, struct args *args)
+{
+ int c;
+
+ static const struct option longopts[] = {
+ { "source", required_argument, NULL, 's' },
+ { "dest", required_argument, NULL, 'd' },
+ { "dest-type", required_argument, NULL, 't' },
+ { "verbose", no_argument, NULL, 'v' },
+ { "version", no_argument, NULL, 'V' },
+ { "help", no_argument, NULL, 'h' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ while ((c = getopt_long(argc, argv, "s:d:t:vVh", longopts, NULL)) != -1)
+ switch (c) {
+ case 's':
+ args->src = strtopid_or_err(
+ optarg,
+ _("Failed to parse PID for -s/--source"));
+ break;
+ case 'd':
+ args->dest = strtopid_or_err(
+ optarg, _("Failed to parse PID for -d/--dest"));
+ break;
+ case 't':
+ args->type = parse_core_sched_type(optarg);
+ break;
+ case 'v':
+ sched_core_verbose = true;
+ break;
+ case 'V':
+ print_version(EXIT_SUCCESS);
+ case 'h':
+ usage();
+ default:
+ errtryhelp(EXIT_FAILURE);
+ }
+
+ if (argc <= optind) {
+ args->cmd = SCHED_CORE_CMD_GET;
+ } else {
+ if (!strcmp(argv[optind], "get"))
+ args->cmd = SCHED_CORE_CMD_GET;
+ else if (!strcmp(argv[optind], "new"))
+ args->cmd = SCHED_CORE_CMD_NEW;
+ else if (!strcmp(argv[optind], "copy"))
+ args->cmd = SCHED_CORE_CMD_COPY;
+ else
+ bad_usage(_("Unknown function"));
+
+ // Since we parsed an extra "option" outside of getopt_long, we have to
+ // increment optind manually.
+ ++optind;
+ }
+
+ if (args->cmd == SCHED_CORE_CMD_GET && args->dest)
+ bad_usage(_("get does not accept the --dest option"));
+
+ if (args->cmd == SCHED_CORE_CMD_NEW && args->src)
+ bad_usage(_("new does not accept the --source option"));
+
+ // If the -s/--source option is not specified, it defaults to the PID
+ // of the current coresched process
+ if (args->cmd != SCHED_CORE_CMD_NEW && !args->src)
+ args->src = getpid();
+
+ // More arguments have been passed, which means that the user wants to run
+ // another program with a core scheduling cookie.
+ if (argc > optind) {
+ switch (args->cmd) {
+ case SCHED_CORE_CMD_GET:
+ bad_usage(_("bad usage of the get function"));
+ break;
+ case SCHED_CORE_CMD_NEW:
+ if (args->dest)
+ bad_usage(_(
+ "new requires either a -d/--dest or a command"));
+ else
+ args->exec_argv_offset = optind;
+ break;
+ case SCHED_CORE_CMD_COPY:
+ if (args->dest)
+ bad_usage(_(
+ "copy requires either a -d/--dest or a command"));
+ else
+ args->exec_argv_offset = optind;
+ break;
+ }
+ } else {
+ if (args->cmd == SCHED_CORE_CMD_NEW && !args->dest)
+ bad_usage(_(
+ "new requires either a -d/--dest or a command"));
+ if (args->cmd == SCHED_CORE_CMD_COPY && !args->dest)
+ bad_usage(_(
+ "copy requires either a -d/--dest or a command"));
+ }
+}
+
+int main(int argc, char **argv)
+{
+ struct args args = { .type = PR_SCHED_CORE_SCOPE_THREAD_GROUP };
+
+ setlocale(LC_ALL, "");
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+ close_stdout_atexit();
+
+ parse_and_verify_arguments(argc, argv, &args);
+
+ if (!is_core_sched_supported())
+ errx(EXIT_FAILURE,
+ _("No support for core scheduling found. Does your kernel "
+ "support CONFIG_SCHED_CORE?"));
+
+ sched_core_cookie cookie;
+
+ switch (args.cmd) {
+ case SCHED_CORE_CMD_GET:
+ cookie = core_sched_get_cookie(args.src);
+ printf(_("cookie of pid %d is 0x%llx\n"), args.src, cookie);
+ break;
+ case SCHED_CORE_CMD_NEW:
+ if (args.exec_argv_offset) {
+ core_sched_exec_with_cookie(&args, argv);
+ } else {
+ core_sched_create_cookie(args.dest, args.type);
+ core_sched_get_and_print_cookie(args.dest);
+ }
+ break;
+ case SCHED_CORE_CMD_COPY:
+ if (args.exec_argv_offset)
+ core_sched_exec_with_cookie(&args, argv);
+ else
+ core_sched_copy_cookie(args.src, args.dest, args.type);
+ break;
+ default:
+ usage();
+ }
+}
diff --git a/tests/commands.sh b/tests/commands.sh
index 5674c5ff0..9eef92ccb 100644
--- a/tests/commands.sh
+++ b/tests/commands.sh
@@ -71,6 +71,7 @@ TS_CMD_COLCRT=${TS_CMD_COLCRT:-"${ts_commandsdir}colcrt"}
TS_CMD_COLRM=${TS_CMD_COLRM:-"${ts_commandsdir}colrm"}
TS_CMD_COL=${TS_CMD_COL:-"${ts_commandsdir}col"}
TS_CMD_COLUMN=${TS_CMD_COLUMN:-"${ts_commandsdir}column"}
+TS_CMD_CORESCHED=${TS_CMD_CORESCHED:-"${ts_commandsdir}coresched"}
TS_CMD_ENOSYS=${TS_CMD_ENOSYS-"${ts_commandsdir}enosys"}
TS_CMD_EJECT=${TS_CMD_EJECT-"${ts_commandsdir}eject"}
TS_CMD_EXCH=${TS_CMD_EXCH-"${ts_commandsdir}exch"}
diff --git a/tests/expected/schedutils/coresched-copy-from-child-to-parent b/tests/expected/schedutils/coresched-copy-from-child-to-parent
new file mode 100644
index 000000000..5b9c40052
--- /dev/null
+++ b/tests/expected/schedutils/coresched-copy-from-child-to-parent
@@ -0,0 +1 @@
+DIFFERENT_COOKIE
diff --git a/tests/expected/schedutils/coresched-copy-from-parent-to-nested-child b/tests/expected/schedutils/coresched-copy-from-parent-to-nested-child
new file mode 100644
index 000000000..ecfc41142
--- /dev/null
+++ b/tests/expected/schedutils/coresched-copy-from-parent-to-nested-child
@@ -0,0 +1 @@
+SAME_COOKIE
diff --git a/tests/expected/schedutils/coresched-get-cookie-own-pid b/tests/expected/schedutils/coresched-get-cookie-own-pid
new file mode 100644
index 000000000..84f182cbe
--- /dev/null
+++ b/tests/expected/schedutils/coresched-get-cookie-own-pid
@@ -0,0 +1 @@
+cookie of pid OWN_PID is PARENT_COOKIE
diff --git a/tests/expected/schedutils/coresched-get-cookie-parent-pid b/tests/expected/schedutils/coresched-get-cookie-parent-pid
new file mode 100644
index 000000000..e183e0402
--- /dev/null
+++ b/tests/expected/schedutils/coresched-get-cookie-parent-pid
@@ -0,0 +1 @@
+cookie of pid PARENT_PID is PARENT_COOKIE
diff --git a/tests/expected/schedutils/coresched-new-child-with-new-cookie b/tests/expected/schedutils/coresched-new-child-with-new-cookie
new file mode 100644
index 000000000..5b9c40052
--- /dev/null
+++ b/tests/expected/schedutils/coresched-new-child-with-new-cookie
@@ -0,0 +1 @@
+DIFFERENT_COOKIE
diff --git a/tests/expected/schedutils/coresched-set-cookie-parent-pid.err b/tests/expected/schedutils/coresched-set-cookie-parent-pid.err
new file mode 100644
index 000000000..e7318ffc2
--- /dev/null
+++ b/tests/expected/schedutils/coresched-set-cookie-parent-pid.err
@@ -0,0 +1 @@
+coresched: set cookie of PID PARENT_PID to PARENT_COOKIE
diff --git a/tests/expected/schedutils/set-cookie-parent-pid b/tests/expected/schedutils/set-cookie-parent-pid
new file mode 100644
index 000000000..e7318ffc2
--- /dev/null
+++ b/tests/expected/schedutils/set-cookie-parent-pid
@@ -0,0 +1 @@
+coresched: set cookie of PID PARENT_PID to PARENT_COOKIE
diff --git a/tests/ts/schedutils/coresched b/tests/ts/schedutils/coresched
new file mode 100755
index 000000000..debb8cbfc
--- /dev/null
+++ b/tests/ts/schedutils/coresched
@@ -0,0 +1,89 @@
+#!/bin/bash
+# SPDX-License-Identifier: EUPL-1.2
+#
+# This file is part of util-linux
+#
+# Copyright (C) 2024 Thijs Raymakers
+# Licensed under the EUPL v1.2
+
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="coresched"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+ts_check_test_command "$TS_CMD_CORESCHED"
+ts_check_prog "tee"
+ts_check_prog "sed"
+
+# If there is no kernel support, skip the test suite
+CORESCHED_TEST_KERNEL_SUPPORT_CMD=$($TS_CMD_CORESCHED 2>&1)
+if [[ $CORESCHED_TEST_KERNEL_SUPPORT_CMD == *"CONFIG_SCHED_CORE"* ]]; then
+ ts_skip "Kernel has no CONFIG_SCHED_CORE support"
+fi
+
+# Kernel and the machine must support SMT
+CORESCHED_HAS_SMT_SUPPORT=$(</sys/devices/system/cpu/smt/control)
+if [[ "$CORESCHED_HAS_SMT_SUPPORT" != "on" ]]; then
+ ts_skip "SMT is unavailable (state: $CORESCHED_HAS_SMT_SUPPORT)"
+fi
+
+# The output of coresched contains PIDs and core scheduling cookies, both of which should be
+# assumed to be random values as we have no control over them. The tests replace these values
+# with sed before writing them to the output file, so it can match the expected output file.
+# - The PID of this bash script is replaced with the placeholder `OWN_PID`
+# - The core scheduling cookie of this bash script is replaced by `COOKIE`
+# - Any other cookie is replaced by `DIFFERENT_COOKIE`
+# The behavior of coresched does not depend on the exact values of these cookies, so using
+# placeholder values does not change the behavior tests.
+ts_init_subtest "set-cookie-parent-pid"
+CORESCHED_OUTPUT=$( ($TS_CMD_CORESCHED -v new -d $$ \
+ | tee -a "$TS_OUTPUT") 3>&1 1>&2 2>&3 \
+ | sed "s/$$/PARENT_PID/g")
+CORESCHED_PARENT_COOKIE=$(echo "$CORESCHED_OUTPUT" | sed 's/^.*\(0x.*$\)/\1/g')
+if [ -z "$CORESCHED_PARENT_COOKIE" ]; then
+ ts_failed "empty value for CORESCHED_PARENT_COOKIE"
+fi
+CORESCHED_OUTPUT=$(echo "$CORESCHED_OUTPUT" \
+ | sed "s/$CORESCHED_PARENT_COOKIE/PARENT_COOKIE/g")
+echo "$CORESCHED_OUTPUT" >> "$TS_ERRLOG"
+ts_finalize_subtest
+
+ts_init_subtest "get-cookie-parent-pid"
+$TS_CMD_CORESCHED get -s $$ 2>> "$TS_ERRLOG" \
+ | sed -e "s/$$/PARENT_PID/g" \
+ -e "s/$CORESCHED_PARENT_COOKIE/PARENT_COOKIE/g" >> "$TS_OUTPUT"
+ts_finalize_subtest
+
+ts_init_subtest "get-cookie-own-pid"
+$TS_CMD_CORESCHED get 2>> "$TS_ERRLOG" \
+ | sed -e "s/pid [0-9]\+/pid OWN_PID/g" \
+ -e "s/$CORESCHED_PARENT_COOKIE/PARENT_COOKIE/g" >> "$TS_OUTPUT"
+ts_finalize_subtest
+
+ts_init_subtest "new-child-with-new-cookie"
+$TS_CMD_CORESCHED new -- "$TS_CMD_CORESCHED" get 2>> "$TS_ERRLOG" \
+ | sed -e 's/^.*\(0x.*$\)/\1/g' \
+ -e "s/$CORESCHED_PARENT_COOKIE/SAME_COOKIE/g" \
+ -e "s/0x.*$/DIFFERENT_COOKIE/g" >> "$TS_OUTPUT"
+ts_finalize_subtest
+
+ts_init_subtest "copy-from-parent-to-nested-child"
+$TS_CMD_CORESCHED new -- /bin/bash -c \
+ "$TS_CMD_CORESCHED copy -s $$ -- $TS_CMD_CORESCHED get" \
+2>> "$TS_ERRLOG" \
+ | sed -e 's/^.*\(0x.*$\)/\1/g' \
+ -e "s/$CORESCHED_PARENT_COOKIE/SAME_COOKIE/g" \
+ -e "s/0x.*$/DIFFERENT_COOKIE/g" >> "$TS_OUTPUT"
+ts_finalize_subtest
+
+ts_init_subtest "copy-from-child-to-parent"
+$TS_CMD_CORESCHED new -- /bin/bash -c \
+ "$TS_CMD_CORESCHED copy -s \$\$ -d $$"
+$TS_CMD_CORESCHED get 2>> "$TS_ERRLOG" \
+ | sed -e 's/^.*\(0x.*$\)/\1/g' \
+ -e "s/$CORESCHED_PARENT_COOKIE/SAME_COOKIE/g" \
+ -e "s/0x.*$/DIFFERENT_COOKIE/g" >> "$TS_OUTPUT"
+ts_finalize_subtest
+
+ts_finalize
--
2.44.0
^ permalink raw reply related
* Re: [PATCH v2] flock: add support for using fcntl() with open file description locks
From: Karel Zak @ 2024-04-25 13:55 UTC (permalink / raw)
To: Rasmus Villemoes; +Cc: util-linux, Masatake YAMATO
In-Reply-To: <20240423120819.571181-1-rasmus.villemoes@prevas.dk>
On Tue, Apr 23, 2024 at 02:08:19PM +0200, Rasmus Villemoes wrote:
> configure.ac | 6 ++++
> meson.build | 3 ++
> sys-utils/flock.c | 82 +++++++++++++++++++++++++++++++++++++++++++++--
> 3 files changed, 89 insertions(+), 2 deletions(-)
Thanks, created pull-request to check it by our CI.
https://github.com/util-linux/util-linux/pull/2993
Karel
--
Karel Zak <kzak@redhat.com>
http://karelzak.blogspot.com
^ permalink raw reply
* [PATCH v3] flock: add support for using fcntl() with open file description locks
From: Rasmus Villemoes @ 2024-04-25 9:44 UTC (permalink / raw)
To: util-linux; +Cc: Masatake YAMATO, Karel Zak, Rasmus Villemoes
Currently, there is no way for shell scripts to safely access
resources protected by POSIX locking (fcntl with the F_SETLK/F_SETLKW
commands). For example, the glibc function lckpwdf(), used to
protect access to the /etc/shadow database, works by taking a
F_SETLKW on /etc/.pwd.lock .
Due to the odd semantics of POSIX locking (e.g. released when any file
descriptor associated to the inode is closed), we cannot usefully
directly expose the POSIX F_SETLK/F_SETLKW commands. However, linux
3.15 introduced F_OFD_SETLK[W], with semantics wrt. ownership and
release better matching those of flock(2), and crucially they do
conflict with locks obtained via F_SETLK[W]. With this, a shell script
can do
exec 4> /etc/.pwd.lock
flock --fcntl 4
<access/modify /etc/shadow ...>
flock --fcntl --unlock 4 # or just exit
without conflicting with passwd(1) or other utilities that
access/modify /etc/shadow.
No single-letter shorthand is defined for the option, because this is
somewhat low-level and the user really needs to know what he is doing.
Also, this leaves the door open for teaching --fcntl to accept an
optional argument: "ofd", the default, and "posix", should anyone find
a use for flock(1) taking a F_SETLK[W] lock.
Signed-off-by: Rasmus Villemoes <rasmus.villemoes@prevas.dk>
---
v3:
- Replace configure-time checking for F_OFD_ by just hard-coding the
proper values in flock.c if the system headers don't provide them.
- Consequently, drop all HAVE_FCNTL_OFD_LOCKS guards.
v2:
- Shorten option name to --fcntl instead of --fcntl-ofd.
- Use a do_lock() helper function switching on the API to use, making
the while () condition easier to read and making it simpler to add
the mentioned --fcntl=posix should the need arise.
- Fix up places that need HAVE_FCNTL_OFD_LOCKS guarding.
sys-utils/flock.c | 78 +++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 76 insertions(+), 2 deletions(-)
diff --git a/sys-utils/flock.c b/sys-utils/flock.c
index 7d878ff81..c42c9da51 100644
--- a/sys-utils/flock.c
+++ b/sys-utils/flock.c
@@ -48,6 +48,17 @@
#include "monotonic.h"
#include "timer.h"
+#ifndef F_OFD_GETLK
+#define F_OFD_GETLK 36
+#define F_OFD_SETLK 37
+#define F_OFD_SETLKW 38
+#endif
+
+enum {
+ API_FLOCK,
+ API_FCNTL_OFD,
+};
+
static void __attribute__((__noreturn__)) usage(void)
{
fputs(USAGE_HEADER, stdout);
@@ -70,6 +81,7 @@ static void __attribute__((__noreturn__)) usage(void)
fputs(_( " -o, --close close file descriptor before running command\n"), stdout);
fputs(_( " -c, --command <command> run a single command string through the shell\n"), stdout);
fputs(_( " -F, --no-fork execute command without forking\n"), stdout);
+ fputs(_( " --fcntl use fcntl(F_OFD_SETLK) rather than flock()\n"), stdout);
fputs(_( " --verbose increase verbosity\n"), stdout);
fputs(USAGE_SEPARATOR, stdout);
fprintf(stdout, USAGE_HELP_OPTIONS(26));
@@ -126,6 +138,49 @@ static void __attribute__((__noreturn__)) run_program(char **cmd_argv)
_exit((errno == ENOMEM) ? EX_OSERR : EX_UNAVAILABLE);
}
+static int flock_to_fcntl_type(int op)
+{
+ switch (op) {
+ case LOCK_EX:
+ return F_WRLCK;
+ case LOCK_SH:
+ return F_RDLCK;
+ case LOCK_UN:
+ return F_UNLCK;
+ default:
+ errx(EX_SOFTWARE, _("internal error, unknown operation %d"), op);
+ }
+}
+
+static int fcntl_lock(int fd, int op, int block)
+{
+ struct flock arg = {
+ .l_type = flock_to_fcntl_type(op),
+ .l_whence = SEEK_SET,
+ .l_start = 0,
+ .l_len = 0,
+ };
+ int cmd = (block & LOCK_NB) ? F_OFD_SETLK : F_OFD_SETLKW;
+ return fcntl(fd, cmd, &arg);
+}
+
+static int do_lock(int api, int fd, int op, int block)
+{
+ switch (api) {
+ case API_FLOCK:
+ return flock(fd, op | block);
+ case API_FCNTL_OFD:
+ return fcntl_lock(fd, op, block);
+ /*
+ * Should never happen, api can never have values other than
+ * API_*.
+ */
+ default:
+ errx(EX_SOFTWARE, _("internal error, unknown api %d"), api);
+ }
+}
+
+
int main(int argc, char *argv[])
{
struct ul_timer timer;
@@ -140,6 +195,7 @@ int main(int argc, char *argv[])
int no_fork = 0;
int status;
int verbose = 0;
+ int api = API_FLOCK;
struct timeval time_start = { 0 }, time_done = { 0 };
/*
* The default exit code for lock conflict or timeout
@@ -149,7 +205,8 @@ int main(int argc, char *argv[])
char **cmd_argv = NULL, *sh_c_argv[4];
const char *filename = NULL;
enum {
- OPT_VERBOSE = CHAR_MAX + 1
+ OPT_VERBOSE = CHAR_MAX + 1,
+ OPT_FCNTL,
};
static const struct option long_options[] = {
{"shared", no_argument, NULL, 's'},
@@ -163,6 +220,7 @@ int main(int argc, char *argv[])
{"close", no_argument, NULL, 'o'},
{"no-fork", no_argument, NULL, 'F'},
{"verbose", no_argument, NULL, OPT_VERBOSE},
+ {"fcntl", no_argument, NULL, OPT_FCNTL},
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'V'},
{NULL, 0, NULL, 0}
@@ -217,6 +275,9 @@ int main(int argc, char *argv[])
if (conflict_exit_code < 0 || conflict_exit_code > 255)
errx(EX_USAGE, _("exit code out of range (expected 0 to 255)"));
break;
+ case OPT_FCNTL:
+ api = API_FCNTL_OFD;
+ break;
case OPT_VERBOSE:
verbose = 1;
break;
@@ -234,6 +295,13 @@ int main(int argc, char *argv[])
errx(EX_USAGE,
_("the --no-fork and --close options are incompatible"));
+ /*
+ * For fcntl(F_OFD_SETLK), an exclusive lock requires that the
+ * file is open for write.
+ */
+ if (api != API_FLOCK && type == LOCK_EX)
+ open_flags = O_WRONLY;
+
if (argc > optind + 1) {
/* Run command */
if (!strcmp(argv[optind + 1], "-c") ||
@@ -280,9 +348,15 @@ int main(int argc, char *argv[])
if (verbose)
gettime_monotonic(&time_start);
- while (flock(fd, type | block)) {
+ while (do_lock(api, fd, type, block)) {
switch (errno) {
case EWOULDBLOCK:
+ /*
+ * Per the man page, for fcntl(), EACCES may
+ * be returned and means the same as
+ * EAGAIN/EWOULDBLOCK.
+ */
+ case EACCES:
/* -n option set and failed to lock. */
if (verbose)
warnx(_("failed to get lock"));
--
2.40.1.1.g1c60b9335d
^ permalink raw reply related
* Re: [PATCH v2] flock: add support for using fcntl() with open file description locks
From: Karel Zak @ 2024-04-25 9:28 UTC (permalink / raw)
To: Rasmus Villemoes; +Cc: util-linux, Masatake YAMATO
In-Reply-To: <fad6d1c0-00e0-4429-9d33-74b2179c0a83@prevas.dk>
On Thu, Apr 25, 2024 at 09:36:06AM +0200, Rasmus Villemoes wrote:
> Hm, actually, since the values of F_OFD_ are the same across all
> architectures, and the API is pretty old already, I think it would be
> simpler to just drop the configure time probing and all the HAVE_
> guards, and simply add five lines
>
> #ifndef F_OFD_GETLK
> #define F_OFD_GETLK 36
> #define F_OFD_SETLK 37
> #define F_OFD_SETLKW 38
> #endif
>
> after the #include s. After all, whether or not the constants are in the
> headers util-linux is being built against doesn't really say whether the
> kernel it ends up being run on has support or not. Then I'll just
> include a note in the documentation that use of --fcntl only works on
> kernels >= 3.14 (besides, it would be really cumbersome, maybe even
> impossible, to have the man page not mention --fcntl even if flock was
> built without that option in its --help output).
I agree, it is usually better to not affect the --help output and
options parsing (using getopt_long() functions) with #ifdefs.
Karel
--
Karel Zak <kzak@redhat.com>
http://karelzak.blogspot.com
^ permalink raw reply
* Re: [PATCH v2] flock: add support for using fcntl() with open file description locks
From: Rasmus Villemoes @ 2024-04-25 7:36 UTC (permalink / raw)
To: util-linux; +Cc: Masatake YAMATO, Karel Zak
In-Reply-To: <20240423120819.571181-1-rasmus.villemoes@prevas.dk>
On 23/04/2024 14.08, Rasmus Villemoes wrote:
> Currently, there is no way for shell scripts to safely access
> resources protected by POSIX locking (fcntl with the F_SETLK/F_SETLKW
> commands). For example, the glibc function lckpwdf(), used to
> protect access to the /etc/shadow database, works by taking a
> F_SETLKW on /etc/.pwd.lock .
>
> Due to the odd semantics of POSIX locking (e.g. released when any file
> descriptor associated to the inode is closed), we cannot usefully
> directly expose the POSIX F_SETLK/F_SETLKW commands. However, linux
> 3.15 introduced F_OFD_SETLK[W], with semantics wrt. ownership and
> release better matching those of flock(2), and crucially they do
> conflict with locks obtained via F_SETLK[W]. With this, a shell script
> can do
>
> exec 4> /etc/.pwd.lock
> flock --fcntl 4
> <access/modify /etc/shadow ...>
> flock --fcntl --unlock 4 # or just exit
>
> without conflicting with passwd(1) or other utilities that
> access/modify /etc/shadow.
>
> No single-letter shorthand is defined for the option, because this is
> somewhat low-level and the user really needs to know what he is doing.
>
> Also, this leaves the door open for teaching --fcntl to accept an
> optional argument: "ofd", the default, and "posix", should anyone find
> a use for flock(1) taking a F_SETLK[W] lock.
>
> Signed-off-by: Rasmus Villemoes <rasmus.villemoes@prevas.dk>
> ---
> v2:
>
> - Shorten option name to --fcntl instead of --fcntl-ofd.
>
> - Use a do_lock() helper function switching on the API to use, making
> the while () condition easier to read and making it simpler to add
> the mentioned --fcntl=posix should the need arise.
>
> - Fix up places that need HAVE_FCNTL_OFD_LOCKS guarding.
Hm, actually, since the values of F_OFD_ are the same across all
architectures, and the API is pretty old already, I think it would be
simpler to just drop the configure time probing and all the HAVE_
guards, and simply add five lines
#ifndef F_OFD_GETLK
#define F_OFD_GETLK 36
#define F_OFD_SETLK 37
#define F_OFD_SETLKW 38
#endif
after the #include s. After all, whether or not the constants are in the
headers util-linux is being built against doesn't really say whether the
kernel it ends up being run on has support or not. Then I'll just
include a note in the documentation that use of --fcntl only works on
kernels >= 3.14 (besides, it would be really cumbersome, maybe even
impossible, to have the man page not mention --fcntl even if flock was
built without that option in its --help output).
Rasmus
^ permalink raw reply
* Re: [RFC] ipcs for POSIX IPC
From: Masatake YAMATO @ 2024-04-24 13:15 UTC (permalink / raw)
To: kzak; +Cc: paithankarprasanna, util-linux
In-Reply-To: <20240424095240.l2fzrswgtvaqpv2o@ws.net.home>
On Wed, 24 Apr 2024 11:52:40 +0200, Karel Zak wrote:
> On Wed, Apr 24, 2024 at 04:10:48AM +0530, Prasanna Paithankar wrote:
>> The 'ipcs' (and 'ipcrm') command provides information on (or removes
>> some) System V IPC resources. I'd like to know why no similar utility
>> for POSIX IPC has existed for a long time. I would like to know if
>> such a tool exists in case I missed it. If not, I will provide patches
>> to ipcs and ipcrm (or should I separate the functionality into a new
>> utility).
>
> I would suggest improving 'lsipc' instead of using the old 'ipcs'.
>
> The question is where to find information about POSIX IPC. For System
> V, there is /proc/sysvipc, but there is no equivalent for POSIX (or I
> am not aware of it). It seems that the only way to gather this
> information is by scanning all processes' memory maps for /dev/shm.
> This could be achieved by using lsfd.
I read the related man pages:
shm_overview(7) says shm_open(3) may make a file at /dev/shm.
With the following test prgram, I saw it created /dev/shm/X.
#include <sys/mman.h>
#include <sys/stat.h> /* For mode constants */
#include <fcntl.h> /* For O_* constants */
int
main(void)
{
int fd = shm_open("X", O_CREAT | O_EXCL | O_RDWR, 0600);
while (1);
return 0;
}
sem_overview(7) says:
On Linux, named semaphores are created in a virtual filesystem, nor‐
mally mounted under /dev/shm, with names of the form sem.somename.
As Karel wrote, lsfd can list them if a process do-mmap them.
lsfd doesn't distinguish shm and sem.
mq_overview(7) doesn't say the defatil about the visibility. I inspected the visibility
of mq when addng mq support to lsfd.
The list of mqueue is available if "mqueue" file systems is mounted.
See mqueue_fs_type in ipc/mqueue.c of Linux.
On Fedora, the filesystem is mounted to /dev/mqueue by default. However, some
platforms may not mount it by default.
Here is my idea for listing mqueue:
for mnt_ns in $all_mnt_ns; do
if mqueue_fs_is_found_in /proc/mounts; then
ls the_mount_point
else
for p in $all_processes; do
for fd in $all_fd_in_$p; do
if is_mqueue_fd $fd
echo the_information_about $fd
fi
done
done | uniq
fi
done
lsfd can list mqueues as far as they are opened by processes.
We can use get_minor_for_mqueue and is_mqueue_dev in lsfd-cmd/file.c
when implementing of is_mqueue_fd.
Mounting temporarily the mqueue file system in lsipc is an alternative
way.
Masatake YAMATO
> Karel
>
>>
>> Yours sincerely
>> Prasanna Paithankar
>>
>
> --
> Karel Zak <kzak@redhat.com>
> http://karelzak.blogspot.com
>
>
^ permalink raw reply
* Re: umount -r broken due to "mountinfo unnecessary"
From: Karel Zak @ 2024-04-24 10:15 UTC (permalink / raw)
To: Krzysztof Olędzki; +Cc: util-linux
In-Reply-To: <1350349b-8465-4ce6-8dc9-55a32b84dc39@ans.pl>
On Tue, Apr 23, 2024 at 07:35:18AM -0700, Krzysztof Olędzki wrote:
> When is the next release planned?
I plan to release v2.40.1 next week.
> Also, do you expect a backport to stable/v2.39 and v2.39.5?
I have cherry-picked it to stable/v2.39. Currently, I have no plans
for v2.39.5.
Karel
--
Karel Zak <kzak@redhat.com>
http://karelzak.blogspot.com
^ permalink raw reply
* Re: [RFC] ipcs for POSIX IPC
From: Karel Zak @ 2024-04-24 9:52 UTC (permalink / raw)
To: Prasanna Paithankar; +Cc: util-linux
In-Reply-To: <CAOfrUuZ8fL3kz=p2Pwh5JN6Nm9UvE4NPtcikNFCL8LC7r5FW0g@mail.gmail.com>
On Wed, Apr 24, 2024 at 04:10:48AM +0530, Prasanna Paithankar wrote:
> The 'ipcs' (and 'ipcrm') command provides information on (or removes
> some) System V IPC resources. I'd like to know why no similar utility
> for POSIX IPC has existed for a long time. I would like to know if
> such a tool exists in case I missed it. If not, I will provide patches
> to ipcs and ipcrm (or should I separate the functionality into a new
> utility).
I would suggest improving 'lsipc' instead of using the old 'ipcs'.
The question is where to find information about POSIX IPC. For System
V, there is /proc/sysvipc, but there is no equivalent for POSIX (or I
am not aware of it). It seems that the only way to gather this
information is by scanning all processes' memory maps for /dev/shm.
This could be achieved by using lsfd.
Karel
>
> Yours sincerely
> Prasanna Paithankar
>
--
Karel Zak <kzak@redhat.com>
http://karelzak.blogspot.com
^ permalink raw reply
* Re: RFE: hardlink: support specifying max_size too?
From: Karel Zak @ 2024-04-24 9:37 UTC (permalink / raw)
To: Mikko Rantalainen; +Cc: util-linux
In-Reply-To: <0aa615c2-8e17-4eb3-9a25-c8af39b35d81@peda.net>
Hi Mikko,
On Tue, Apr 23, 2024 at 04:58:10PM +0300, Mikko Rantalainen wrote:
> I have huge directory hierarchies that I would like to run hardlink
> against but comparing a lot of files against each other results in high
> RAM usage because so much of the file metadata is kept in memory.
Good point. I have tried to optimize the content comparison (using the
kernel crypto API), but the binary tree is still the original
implementation and there is probably room for further optimization.
Perhaps storing all 'struct stat' information for every file is
excessive, as there is information that we do not need (such as atime,
ctime, st_blksize, st_blocks). Some information is only necessary if
respect_{mode,owner,time,xattrs} are enabled.
The tree also contains paths for all the files. If you have many
subdirectories or long directory names, there is a lot of duplicate
data in the binary tree. One possible solution could be to keep
directory paths in a separate hash table and only store pointers to
the names table in the metadata tree.
Another problem I see is that the hardlink keeps the entire
binary tree in memory during the second stage when it compares file
contents in the visitor() function. However, at this point, we do not
need the tree entries that are already unique and will never be used
to compare file contents.
> Could you add max_size (--maximum-size) option in addition to min_size
> (--minimum-size)? This would allow splitting the work into small
> fragments where hardlink only needs to process files in given range and
> immediately ignore all other files. Or it could be used to run full
> linking in multiple parallel tasks with sensible RAM requirements if you
> can run hardlink without size limitations (e.g. one task for 1–1MB
> files, another for 1MB–10MB and third task for files bigger than 10MB).
This is not a trivial task. It would be better to begin with
optimizing memory usage before implementing more invasive changes.
I am unsure how you plan to compare all files if the metadata is
stored in multiple independent trees.
> It might also make sense to reorder the test for filesize and regex
> processing in inserter() because testing for size is probably faster
> because the stat() has already been made. Currently the stats.files is
> also increased for files that get ignored by size filter which may not
> be intentional.
Good point, send patch :-)
> I think I could provide patches if I just know which Git repo I should
> use as the basis. Is https://github.com/util-linux/util-linux the
> correct one?
Yes, GitHub is the best repository. You can also use it for pull
requests and reviews.
My suggestion is to add debug messages to see where the problem is,
calculate the size of metadata, the size of paths, and the size of
calculated data checksums. Please share the results.
Karel
--
Karel Zak <kzak@redhat.com>
http://karelzak.blogspot.com
^ permalink raw reply
* [RFC] ipcs for POSIX IPC
From: Prasanna Paithankar @ 2024-04-23 22:40 UTC (permalink / raw)
To: util-linux
Greetings,
The 'ipcs' (and 'ipcrm') command provides information on (or removes
some) System V IPC resources. I'd like to know why no similar utility
for POSIX IPC has existed for a long time. I would like to know if
such a tool exists in case I missed it. If not, I will provide patches
to ipcs and ipcrm (or should I separate the functionality into a new
utility).
Yours sincerely
Prasanna Paithankar
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox