From: Phil Auld <pauld@redhat.com>
To: Thijs Raymakers <thijs@raymakers.nl>
Cc: Karel Zak <kzak@redhat.com>, util-linux@vger.kernel.org
Subject: Re: [PATCH RFC] coresched: Manage core scheduling cookies for tasks
Date: Tue, 26 Mar 2024 10:41:29 -0400 [thread overview]
Message-ID: <20240326144129.GA315070@lorien.usersys.redhat.com> (raw)
In-Reply-To: <20240324200745.yn5krdvi7brdrqga@ws.net.home>
On Sun, Mar 24, 2024 at 09:07:45PM +0100 Karel Zak wrote:
> On Sat, Mar 16, 2024 at 06:10:03PM +0100, Thijs Raymakers wrote:
> > I'm looking for any comments on coresched, a program that allows you to
> > manage core scheduling cookies for tasks.
>
> https://github.com/util-linux/util-linux/pull/2839
>
> Guys, you should sync your work and merge it together :-)
>
> CC: Phil Auld
>
After looking at this some more I'd like to try to add your
pull/push use case to my code instead.
There are some issues I'm having with the arguments in this one.
I think it's a little counter-intuitive.
The exec should not fork first.
And the error handling I think is just not right. I believe prctl()
returns -1 on error and sets errno. This code will report EPERM for all
prtcl errors. While EPERM is likely I don't think it's the only error.
I put a few other comments inline as well.
Cheers,
Phil
> Karel
>
> >
> > === What is Core Scheduling ===
> > Core Scheduling can be used to ensure that certain tasks will never be
> > scheduled on the same physical core. This can be a useful, alternative,
> > mitigation to hardware vulnerabilities like L1tf or MDS.
> > The full software mitigation for these vulnerabilities would be to disable
> > SMT/Hyper-Threading. However, this can be prohibitively expensive and
> > therefore often not done in practice.
> > With Core Scheduling you can mitigate in these issues in some scenarios,
> > while keeping SMT enabled.
> >
> > Core Scheduling works by adding a random "cookie" to a process. Only
> > processes with the same core scheduling cookie are allowed to run on
> > sibling cores. Tasks that trust each other can be given the same
> > cookie and untrusted tasks are given a different cookie.
> > This is important when running VMs that don't trust each other, as
> > it prevents a guest VM to leak data from another guest VM with L1tf or MDS.
> >
> > === Motivation ===
> > The kernel exposes a prctl uapi to manage core scheduling cookies (see
> > https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/core-scheduling.html)
> > Last week, I wanted to use core scheduling on some programs. Adding the
> > prctl calls and recompiling felt a bit inconvenient, so I looked for a
> > program like taskset that could do the job without having to modify the
> > target program. I couldn't find any, and so I wrote a small program that
> > does this. Hopefully it saves the next person some time :)
> >
> > === RFC ===
> > I'm looking forward to any comments that you might have on the patch!
> > Please note that I haven't written the manpage and the bash completion
> > script yet. I first wanted to get some feedback on the program before I
> > start documenting it in more detail.
> >
> > I'm particularly curious about your thoughts on the following things:
> >
> > - General comments about interacting with the program: Do the options
> > make sense? Are there any necessary functions missing? Are the error
> > messages helpful? Is the output too verbose/not verbose enough?
> > - How should the program behave if the prctl core scheduling API is not
> > available? It has been in Linus' tree since november 2021
> > (commit a41b74451b35f7a6529689760eb8c05241feecbc) but it can be
> > disabled with CONFIG_SCHED_CORE=n
This one is tricky. If I recall the error you get is ambiguous in this case
(EINVAL, which can be returned for other reasons). It would be nice to be
able to report that specifically.
> > - Most of the options require the user to have the CAP_SYS_PTRACE
> > capability. Should the program notify the user that the capability
> > is missing when the prctl call returns -EPREM, or does a mention in the
> > man page suffice?
Reporting the correct error message should be enough.
> > - I've currently licensed it under the EUPL v1.2, which is easier to
> > enforce in my jurisdiction than the GPL. It is GPL compatible so it
> > shouldn't be an issue, but if anybody has any remarks on this, please
> > let me know.
The util-linux package is GPL so personally I think it would be good to just
make any new addition to that package also GPL.
> >
> > Thanks for taking the time!
> >
> > Best regards,
> > Thijs Raymakers
> >
> >
> > Signed-off-by: Thijs Raymakers <thijs@raymakers.nl>
> >
> > ---
> > .gitignore | 1 +
> > bash-completion/coresched | 0
> > configure.ac | 12 +-
> > meson.build | 16 +-
> > meson_options.txt | 2 +-
> > schedutils/Makemodule.am | 8 +
> > schedutils/coresched.1.adoc | 16 ++
> > schedutils/coresched.c | 340 ++++++++++++++++++++++++++++++++++++
> > 8 files changed, 389 insertions(+), 6 deletions(-)
> > create mode 100644 bash-completion/coresched
> > create mode 100644 schedutils/coresched.1.adoc
> > create mode 100644 schedutils/coresched.c
> >
> > 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 ab7c98636..3a189a075 100644
> > --- a/configure.ac
> > +++ b/configure.ac
> > @@ -2500,9 +2500,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])]
> > )
> >
> > @@ -2545,6 +2545,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 f7baab7a2..8244c43a9 100644
> > --- a/meson.build
> > +++ b/meson.build
> > @@ -3107,13 +3107,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 7b8cf3f35..3405c1b73 100644
> > --- a/meson_options.txt
> > +++ b/meson_options.txt
> > @@ -162,7 +162,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..60a21cd01
> > --- /dev/null
> > +++ b/schedutils/coresched.1.adoc
> > @@ -0,0 +1,16 @@
> > +//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
> > diff --git a/schedutils/coresched.c b/schedutils/coresched.c
> > new file mode 100644
> > index 000000000..4be8f9fda
> > --- /dev/null
> > +++ b/schedutils/coresched.c
> > @@ -0,0 +1,340 @@
> > +/**
> > + * SPDX-License-Identifier: EUPL-1.2
> > + *
> > + * coresched.c - manage core scheduling cookies for tasks
> > + *
> > + * Copyright (C) 2024 Thijs Raymakers
> > + * Licensed under the EUPL v1.2
> > + */
> > +
> > +#include <getopt.h>
> > +#include <stdbool.h>
> > +#include <stdio.h>
> > +#include <sys/prctl.h>
> > +#include <sys/wait.h>
> > +
> > +#include "c.h"
> > +#include "closestream.h"
> > +#include "nls.h"
> > +#include "strutils.h"
> > +
> > +typedef enum {
> > + SCHED_CORE_SCOPE_PID = PR_SCHED_CORE_SCOPE_THREAD,
> > + SCHED_CORE_SCOPE_TGID = PR_SCHED_CORE_SCOPE_THREAD_GROUP,
> > + SCHED_CORE_SCOPE_PGID = PR_SCHED_CORE_SCOPE_PROCESS_GROUP,
> > +} core_sched_type_t;
> > +
Is this needed? You've made the names a little shorter I guess.
Also some versions of prctl.h don't have the PR_SCHED_CORE_SCOPE* defines
even when they have the base PR_SCHED_CORE macros.
> > +typedef enum {
> > + SCHED_CORE_CMD_NONE = 0,
> > + SCHED_CORE_CMD_GET = 1,
> > + SCHED_CORE_CMD_CREATE = 2,
> > + SCHED_CORE_CMD_COPY = 4,
> > + SCHED_CORE_CMD_EXEC = 8,
> > +} core_sched_cmd_t;
> > +
> > +struct args {
> > + pid_t from_pid;
> > + pid_t to_pid;
> > + core_sched_type_t type;
> > + core_sched_cmd_t cmd;
> > + int exec_argv_offset;
> > +};
> > +
> > +unsigned long core_sched_get_cookie(struct args *args);
> > +void core_sched_create_cookie(struct args *args);
> > +void core_sched_pull_cookie(pid_t from);
> > +void core_sched_push_cookie(pid_t to, core_sched_type_t type);
> > +void core_sched_copy_cookie(struct args *args);
> > +void core_sched_exec_with_cookie(struct args *args, char **argv);
> > +
> > +core_sched_type_t parse_core_sched_type(char *str);
> > +bool verify_arguments(struct args *args);
> > +void parse_arguments(int argc, char **argv, struct args *args);
> > +
> > +unsigned long core_sched_get_cookie(struct args *args)
> > +{
> > + unsigned long cookie = 0;
> > + int prctl_errno = prctl(PR_SCHED_CORE, PR_SCHED_CORE_GET,
> > + args->from_pid, SCHED_CORE_SCOPE_PID, &cookie);
> > + if (prctl_errno) {
> > + errx(-prctl_errno, "Failed to get cookie from PID %d",
> > + args->from_pid);
> > + }
prctl_errno will be 0 on success or -1 on failure. This will report EPERM for
every error.
> > + return cookie;
> > +}
> > +
> > +void core_sched_create_cookie(struct args *args)
> > +{
> > + int prctl_errno = prctl(PR_SCHED_CORE, PR_SCHED_CORE_CREATE,
> > + args->from_pid, args->type, 0);
We are creating a new cookie on from_pid, seems odd.
> > + if (prctl_errno) {
> > + errx(-prctl_errno, "Failed to create cookie for PID %d",
> > + args->from_pid);
> > + }
> > +}
> > +
> > +void core_sched_pull_cookie(pid_t from)
> > +{
> > + int prctl_errno = prctl(PR_SCHED_CORE, PR_SCHED_CORE_SHARE_FROM, from,
> > + SCHED_CORE_SCOPE_PID, 0);
> > + if (prctl_errno) {
> > + errx(-prctl_errno, "Failed to pull cookie from PID %d", from);
> > + }
> > +}
> > +
> > +void core_sched_push_cookie(pid_t to, core_sched_type_t type)
> > +{
> > + int prctl_errno =
> > + prctl(PR_SCHED_CORE, PR_SCHED_CORE_SHARE_TO, to, type, 0);
> > + if (prctl_errno) {
> > + errx(-prctl_errno, "Failed to push cookie to PID %d", to);
> > + }
> > +}
> > +
> > +void core_sched_copy_cookie(struct args *args)
> > +{
> > + core_sched_pull_cookie(args->from_pid);
> > + core_sched_push_cookie(args->to_pid, args->type);
> > +}
> > +
> > +void core_sched_exec_with_cookie(struct args *args, char **argv)
> > +{
> > + if (!args->exec_argv_offset) {
> > + errx(EINVAL, "when --exec is provided, a program name "
> > + "has to be given.");
> > + }
> > +
> > + // Move the argument list to the first argument of the program
> > + argv = &argv[args->exec_argv_offset];
> > +
> > + pid_t pid = fork();
> > + if (pid == -1) {
> > + errx(errno, "Failed to spawn new process");
> > + }
Don't fork here. Just exec to the new program, as the other wrapper
programs like taskset do.
> > +
> > + if (!pid) {
> > + // 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->from_pid) {
> > + core_sched_pull_cookie(args->from_pid);
> > + } else {
> > + args->from_pid = getpid();
> > + core_sched_create_cookie(args);
> > + }
> > + if (execvp(argv[0], argv)) {
> > + errexec(argv[0]);
> > + }
> > + } else {
> > + int status = 0;
> > + waitpid(pid, &status, 0);
> > + exit(status);
> > + }
> > +}
> > +
> > +core_sched_type_t parse_core_sched_type(char *str)
> > +{
> > + if (!strncmp(str, "pid\0", 4)) {
> > + return SCHED_CORE_SCOPE_PID;
> > + } else if (!strncmp(str, "tgid\0", 5)) {
> > + return SCHED_CORE_SCOPE_TGID;
> > + } else if (!strncmp(str, "pgid\0", 5)) {
> > + return SCHED_CORE_SCOPE_PGID;
> > + }
> > +
> > + errx(EINVAL, "'%s' is an invalid option. Must be one of pid/tgid/pgid",
> > + str);
> > + __builtin_unreachable();
> > +}
> > +
> > +static void __attribute__((__noreturn__)) usage(void)
> > +{
> > + fputs(USAGE_HEADER, stdout);
> > + fprintf(stdout, _(" %s --get <PID>\n"), program_invocation_short_name);
> > + fprintf(stdout, _(" %s --new <PID> [-t <TYPE>]\n"),
> > + program_invocation_short_name);
> > + fprintf(stdout, _(" %s --copy -s <PID> -d <PID> [-t <TYPE>]\n"),
> > + program_invocation_short_name);
> > + fprintf(stdout, _(" %s --exec [-s <PID>] -- PROGRAM ARGS... \n"),
> > + program_invocation_short_name);
There are 4 different arguments that take a pid when there are really
only at most 2 needed.
"Get" could just be the default with no arguments given.
> > +
> > + fputs(USAGE_SEPARATOR, stdout);
> > + fputsln(_("Manage core scheduling cookies for tasks."), stdout);
> > +
> > + fputs(USAGE_FUNCTIONS, stdout);
> > + fputsln(_(" -g, --get <PID> get the core scheduling cookie of a PID"),
> > + stdout);
> > + fputsln(_(" -n, --new <PID> assign a new core scheduling cookie to PID"),
> > + stdout);
> > + fputsln(_(" -c, --copy copy the core scheduling cookie from PID to\n"
> > + " another PID, requires the --source and --dest option"),
> > + stdout);
> > + fputsln(_(" -e, --exec execute a program with a new core scheduling\n"
> > + " cookie."),
> > + stdout);
> > +
> > + fputs(USAGE_OPTIONS, stdout);
> > + fputsln(_(" -s, --source <PID> where to copy the core scheduling cookie from."),
> > + stdout);
> > + fputsln(_(" -d, --dest <PID> where to copy the core scheduling cookie to."),
> > + stdout);
> > + fputsln(_(" -t, --type type of the destination PID, or the type of\n"
> > + " the PID when a new core scheduling cookie\n"
> > + " is created. Can be one of the following:\n"
> > + " pid, tgid or pgid. Defaults to tgid."),
> > + stdout);
> > + fputs(USAGE_SEPARATOR, stdout);
> > + fprintf(stdout,
> > + USAGE_HELP_OPTIONS(
> > + 25)); /* char offset to align option descriptions */
> > + fprintf(stdout, USAGE_MAN_TAIL("coresched(1)"));
> > + exit(EXIT_SUCCESS);
> > +}
> > +
> > +bool verify_arguments(struct args *args)
> > +{
> > + if (args->cmd == SCHED_CORE_CMD_NONE) {
> > + usage();
> > + }
> > +
> > + // Check if the value of args->cmd is a power of 2
> > + // In that case, only a single function option was set.
> > + if (!(args->cmd && !(args->cmd & (args->cmd - 1)))) {
> > + errx(EINVAL, "Cannot do more than one function at a time.");
> > + }
> > +
> > + if (args->from_pid < 0) {
> > + errx(EINVAL, "source PID cannot be negative");
> > + }
> > +
> > + if (args->to_pid < 0) {
> > + errx(EINVAL, "destination PID cannot be negative");
> > + }
> > +
> > + if (args->from_pid == 0 && args->cmd == SCHED_CORE_CMD_COPY) {
> > + errx(EINVAL, "valid argument to --source is required");
> > + }
> > +
> > + if (args->to_pid == 0 && args->cmd == SCHED_CORE_CMD_COPY) {
> > + errx(EINVAL, "valid argument to --dest is required");
> > + }
> > +
> > + if (args->from_pid == 0 && args->cmd != SCHED_CORE_CMD_EXEC) {
> > + errx(EINVAL, "PID cannot be zero");
> > + }
> > +
> > + return true;
> > +}
> > +
> > +void parse_arguments(int argc, char **argv, struct args *args)
> > +{
> > + int c;
> > +
> > + enum {
> > + OPT_GET = 'g',
> > + OPT_NEW = 'n',
> > + OPT_COPY = 'c',
> > + OPT_EXEC = 'e',
> > + OPT_SRC = 's',
> > + OPT_DEST = 'd',
> > + OPT_TYPE = 't',
> > + OPT_VERSION = 'V',
> > + OPT_HELP = 'h'
> > + };
This seems over-engineered. You have to specificy the characters
in the getopt_long call anyway so this just complicates the code for
no reason it seems to me.
> > +
> > + static const struct option longopts[] = {
> > + { "get", required_argument, NULL, OPT_GET },
> > + { "new", required_argument, NULL, OPT_NEW },
> > + { "copy", no_argument, NULL, OPT_COPY },
> > + { "exec", no_argument, NULL, OPT_EXEC },
> > + { "source", required_argument, NULL, OPT_SRC },
> > + { "destination", required_argument, NULL, OPT_DEST },
> > + { "type", required_argument, NULL, OPT_TYPE },
> > + { "version", no_argument, NULL, OPT_VERSION },
> > + { "help", no_argument, NULL, OPT_HELP },
> > + { NULL, 0, NULL, 0 }
> > + };
> > +
> > + while ((c = getopt_long(argc, argv, "g:n:ces:d:t:Vh", longopts,
> > + NULL)) != -1)
> > + switch (c) {
> > + case OPT_GET:
> > + args->cmd |= SCHED_CORE_CMD_GET;
> > + args->from_pid = strtos32_or_err(
> > + optarg, "Failed to parse PID for --get");
> > + break;
> > + case OPT_NEW:
> > + args->cmd |= SCHED_CORE_CMD_CREATE;
> > + args->from_pid = strtos32_or_err(
> > + optarg, "Failed to parse PID for --new");
> > + break;
> > + case OPT_COPY:
> > + args->cmd |= SCHED_CORE_CMD_COPY;
> > + break;
> > + case OPT_EXEC:
> > + args->cmd |= SCHED_CORE_CMD_EXEC;
> > + break;
> > + case OPT_SRC:
> > + args->from_pid = strtos32_or_err(
> > + optarg, "Failed to parse PID for --source");
> > + break;
> > + case OPT_DEST:
> > + args->to_pid = strtos32_or_err(
> > + optarg, "Failed to parse PID for --dest");
> > + break;
> > + case OPT_TYPE:
> > + args->type = parse_core_sched_type(optarg);
> > + break;
> > + case OPT_VERSION:
> > + print_version(EXIT_SUCCESS);
> > + case OPT_HELP:
> > + usage();
> > + default:
> > + errtryhelp(EXIT_FAILURE);
> > + }
> > +
> > + if (argc > optind) {
> > + args->exec_argv_offset = optind;
> > + }
> > + verify_arguments(args);
> > +}
> > +
> > +int main(int argc, char **argv)
> > +{
> > + struct args arguments = { 0 };
> > + arguments.type = SCHED_CORE_SCOPE_TGID;
> > +
> > + setlocale(LC_ALL, "");
> > + bindtextdomain(PACKAGE, LOCALEDIR);
> > + textdomain(PACKAGE);
> > + close_stdout_atexit();
> > +
> > + parse_arguments(argc, argv, &arguments);
> > +
> > + unsigned long cookie = 0;
> > + switch (arguments.cmd) {
> > + case SCHED_CORE_CMD_GET:
> > + cookie = core_sched_get_cookie(&arguments);
> > + if (cookie) {
> > + printf("core scheduling cookie of pid %d is 0x%lx\n",
> > + arguments.from_pid, cookie);
> > + } else {
> > + printf("pid %d doesn't have a core scheduling cookie\n",
> > + arguments.from_pid);
> > + exit(1);
> > + }
> > + break;
> > + case SCHED_CORE_CMD_CREATE:
> > + core_sched_create_cookie(&arguments);
> > + break;
> > + case SCHED_CORE_CMD_COPY:
> > + core_sched_copy_cookie(&arguments);
> > + break;
> > + case SCHED_CORE_CMD_EXEC:
> > + core_sched_exec_with_cookie(&arguments, argv);
> > + break;
> > + default:
> > + usage();
> > + exit(1);
> > + }
> > +}
> > --
> > 2.44.0
> >
> >
>
> --
> Karel Zak <kzak@redhat.com>
> http://karelzak.blogspot.com
>
--
next prev parent reply other threads:[~2024-03-26 14:41 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-03-16 17:10 [PATCH RFC] coresched: Manage core scheduling cookies for tasks Thijs Raymakers
2024-03-24 20:07 ` Karel Zak
2024-03-26 14:41 ` Phil Auld [this message]
2024-03-26 14:45 ` Phil Auld
2024-03-26 17:49 ` [PATCH 0/1] " Thijs Raymakers
2024-03-26 18:13 ` Phil Auld
[not found] ` <20240326201722.gf315070@lorien.usersys.redhat.com>
2024-03-27 12:43 ` [PATCH v2 " Thijs Raymakers
2024-03-27 13:21 ` Phil Auld
2024-03-27 14:18 ` Phil Auld
2024-03-27 15:30 ` [PATCH v3] " Thijs Raymakers
2024-04-01 17:18 ` Thomas Weißschuh
2024-04-04 22:03 ` [PATCH v4] " Thijs Raymakers
2024-04-05 6:26 ` Thomas Weißschuh
2024-04-05 14:14 ` Phil Auld
2024-04-08 21:16 ` [PATCH v5] " Thijs Raymakers
2024-04-09 6:12 ` Thomas Weißschuh
2024-04-09 11:55 ` [PATCH v6] " Thijs Raymakers
2024-04-09 13:44 ` Karel Zak
2024-04-09 14:12 ` Phil Auld
2024-04-10 21:11 ` [PATCH v7] " Thijs Raymakers
2024-04-10 22:15 ` Phil Auld
2024-04-11 11:02 ` [PATCH v8] " Thijs Raymakers
2024-04-11 13:46 ` Phil Auld
2024-04-17 10:31 ` Karel Zak
2024-04-17 11:39 ` [PATCH v9] " Thijs Raymakers
2024-04-23 9:27 ` Karel Zak
2024-04-23 10:19 ` Thomas Weißschuh
2024-04-23 11:12 ` [PATCH v10] " Thijs Raymakers
2024-04-25 15:36 ` [PATCH v11] " Thijs Raymakers
2024-04-25 15:51 ` Thomas Weißschuh
2024-04-25 16:22 ` [PATCH v12] " Thijs Raymakers
2024-04-26 7:59 ` Karel Zak
2024-04-26 18:03 ` Thomas Weißschuh
2024-04-29 8:28 ` Karel Zak
2024-04-17 12:27 ` [PATCH v8] " Phil Auld
2024-03-27 12:43 ` [PATCH v2 1/1] " Thijs Raymakers
2024-03-27 14:09 ` Phil Auld
2024-03-26 19:09 ` [PATCH 0/1] " Phil Auld
2024-03-26 19:26 ` Thijs Raymakers
2024-03-26 20:16 ` Phil Auld
2024-03-26 20:17 ` Phil Auld
2024-03-26 17:49 ` [PATCH 1/1] " Thijs Raymakers
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240326144129.GA315070@lorien.usersys.redhat.com \
--to=pauld@redhat.com \
--cc=kzak@redhat.com \
--cc=thijs@raymakers.nl \
--cc=util-linux@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox