Skip to content

Commit d107bb7

Browse files
committed
nspawn: add a new --cpu-affinity= switch
Similar as the other options added before, this is primarily useful to provide comprehensive OCI runtime compatbility, but might be useful otherwise, too.
1 parent 50ebcf6 commit d107bb7

File tree

6 files changed

+118
-3
lines changed

6 files changed

+118
-3
lines changed

man/systemd-nspawn.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,15 @@
796796
integer in the range -1000…1000.</para></listitem>
797797
</varlistentry>
798798

799+
<varlistentry>
800+
<term><option>--cpu-affinity=</option></term>
801+
802+
<listitem><para>Controls the CPU affinity of the container payload. Takes a comma separated list of CPU numbers
803+
or number ranges (the latter's start and end value separated by dashes). See <citerefentry
804+
project='man-pages'><refentrytitle>sched_setaffinity</refentrytitle><manvolnum>2</manvolnum></citerefentry> for
805+
details.</para></listitem>
806+
</varlistentry>
807+
799808
<varlistentry>
800809
<term><option>--kill-signal=</option></term>
801810

man/systemd.nspawn.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,15 @@
322322
details.</para></listitem>
323323
</varlistentry>
324324

325+
<varlistentry>
326+
<term><varname>CPUAffinity=</varname></term>
327+
328+
<listitem><para>Configures the CPU affinity. This is equivalent to the <option>--cpu-affinity=</option> command
329+
line switch, and takes the same argument. See
330+
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
331+
details.</para></listitem>
332+
</varlistentry>
333+
325334
<varlistentry>
326335
<term><varname>Hostname=</varname></term>
327336

src/nspawn/nspawn-gperf.gperf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ Exec.LimitRTTIME, config_parse_rlimit, RLIMIT_RTTIME, of
5252
Exec.Hostname, config_parse_hostname, 0, offsetof(Settings, hostname)
5353
Exec.NoNewPrivileges, config_parse_tristate, 0, offsetof(Settings, no_new_privileges)
5454
Exec.OOMScoreAdjust, config_parse_oom_score_adjust, 0, 0
55+
Exec.CPUAffinity, config_parse_cpu_affinity, 0, 0
5556
Files.ReadOnly, config_parse_tristate, 0, offsetof(Settings, read_only)
5657
Files.Volatile, config_parse_volatile_mode, 0, offsetof(Settings, volatile_mode)
5758
Files.Bind, config_parse_bind, 0, 0

src/nspawn/nspawn-settings.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "alloc-util.h"
99
#include "cap-list.h"
1010
#include "conf-parser.h"
11+
#include "cpu-set-util.h"
1112
#include "hostname-util.h"
1213
#include "nspawn-network.h"
1314
#include "nspawn-settings.h"
@@ -85,6 +86,7 @@ Settings* settings_free(Settings *s) {
8586
strv_free(s->syscall_blacklist);
8687
rlimit_free_all(s->rlimit);
8788
free(s->hostname);
89+
s->cpuset = cpu_set_mfree(s->cpuset);
8890

8991
strv_free(s->network_interfaces);
9092
strv_free(s->network_macvlan);
@@ -673,3 +675,52 @@ int config_parse_oom_score_adjust(
673675

674676
return 0;
675677
}
678+
679+
int config_parse_cpu_affinity(
680+
const char *unit,
681+
const char *filename,
682+
unsigned line,
683+
const char *section,
684+
unsigned section_line,
685+
const char *lvalue,
686+
int ltype,
687+
const char *rvalue,
688+
void *data,
689+
void *userdata) {
690+
691+
_cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
692+
Settings *settings = data;
693+
int ncpus;
694+
695+
assert(rvalue);
696+
assert(settings);
697+
698+
ncpus = parse_cpu_set_and_warn(rvalue, &cpuset, unit, filename, line, lvalue);
699+
if (ncpus < 0)
700+
return ncpus;
701+
702+
if (ncpus == 0) {
703+
/* An empty assignment resets the CPU list */
704+
settings->cpuset = cpu_set_mfree(settings->cpuset);
705+
settings->cpuset_ncpus = 0;
706+
return 0;
707+
}
708+
709+
if (!settings->cpuset) {
710+
settings->cpuset = TAKE_PTR(cpuset);
711+
settings->cpuset_ncpus = (unsigned) ncpus;
712+
return 0;
713+
}
714+
715+
if (settings->cpuset_ncpus < (unsigned) ncpus) {
716+
CPU_OR_S(CPU_ALLOC_SIZE(settings->cpuset_ncpus), cpuset, settings->cpuset, cpuset);
717+
CPU_FREE(settings->cpuset);
718+
settings->cpuset = TAKE_PTR(cpuset);
719+
settings->cpuset_ncpus = (unsigned) ncpus;
720+
return 0;
721+
}
722+
723+
CPU_OR_S(CPU_ALLOC_SIZE((unsigned) ncpus), settings->cpuset, settings->cpuset, cpuset);
724+
725+
return 0;
726+
}

src/nspawn/nspawn-settings.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
Copyright 2015 Lennart Poettering
88
***/
99

10+
#include <sched.h>
1011
#include <stdio.h>
1112

1213
#include "sd-id128.h"
@@ -52,9 +53,10 @@ typedef enum SettingsMask {
5253
SETTING_HOSTNAME = UINT64_C(1) << 17,
5354
SETTING_NO_NEW_PRIVILEGES = UINT64_C(1) << 18,
5455
SETTING_OOM_SCORE_ADJUST = UINT64_C(1) << 19,
55-
SETTING_RLIMIT_FIRST = UINT64_C(1) << 20, /* we define one bit per resource limit here */
56-
SETTING_RLIMIT_LAST = UINT64_C(1) << (20 + _RLIMIT_MAX - 1),
57-
_SETTINGS_MASK_ALL = (UINT64_C(1) << (20 + _RLIMIT_MAX)) - 1
56+
SETTING_CPU_AFFINITY = UINT64_C(1) << 20,
57+
SETTING_RLIMIT_FIRST = UINT64_C(1) << 21, /* we define one bit per resource limit here */
58+
SETTING_RLIMIT_LAST = UINT64_C(1) << (21 + _RLIMIT_MAX - 1),
59+
_SETTINGS_MASK_ALL = (UINT64_C(1) << (21 + _RLIMIT_MAX)) - 1
5860
} SettingsMask;
5961

6062
typedef struct Settings {
@@ -81,6 +83,8 @@ typedef struct Settings {
8183
int no_new_privileges;
8284
int oom_score_adjust;
8385
bool oom_score_adjust_set;
86+
cpu_set_t *cpuset;
87+
unsigned cpuset_ncpus;
8488

8589
/* [Image] */
8690
int read_only;
@@ -127,3 +131,4 @@ int config_parse_private_users(const char *unit, const char *filename, unsigned
127131
int config_parse_syscall_filter(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
128132
int config_parse_hostname(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
129133
int config_parse_oom_score_adjust(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
134+
int config_parse_cpu_affinity(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);

src/nspawn/nspawn.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include "capability-util.h"
4444
#include "cgroup-util.h"
4545
#include "copy.h"
46+
#include "cpu-set-util.h"
4647
#include "dev-setup.h"
4748
#include "dissect-image.h"
4849
#include "env-util.h"
@@ -207,6 +208,8 @@ static struct rlimit *arg_rlimit[_RLIMIT_MAX] = {};
207208
static bool arg_no_new_privileges = false;
208209
static int arg_oom_score_adjust = 0;
209210
static bool arg_oom_score_adjust_set = false;
211+
static cpu_set_t *arg_cpuset = NULL;
212+
static unsigned arg_cpuset_ncpus = 0;
210213

211214
static void help(void) {
212215

@@ -278,6 +281,7 @@ static void help(void) {
278281
" --rlimit=NAME=LIMIT Set a resource limit for the payload\n"
279282
" --oom-score-adjust=VALUE\n"
280283
" Adjust the OOM score value for the payload\n"
284+
" --cpu-affinity=CPUS Adjust the CPU affinity of the container\n"
281285
" --kill-signal=SIGNAL Select signal to use for shutting down PID 1\n"
282286
" --link-journal=MODE Link up guest journal, one of no, auto, guest, \n"
283287
" host, try-guest, try-host\n"
@@ -457,6 +461,7 @@ static int parse_argv(int argc, char *argv[]) {
457461
ARG_HOSTNAME,
458462
ARG_NO_NEW_PRIVILEGES,
459463
ARG_OOM_SCORE_ADJUST,
464+
ARG_CPU_AFFINITY,
460465
};
461466

462467
static const struct option options[] = {
@@ -514,6 +519,7 @@ static int parse_argv(int argc, char *argv[]) {
514519
{ "system-call-filter", required_argument, NULL, ARG_SYSTEM_CALL_FILTER },
515520
{ "rlimit", required_argument, NULL, ARG_RLIMIT },
516521
{ "oom-score-adjust", required_argument, NULL, ARG_OOM_SCORE_ADJUST },
522+
{ "cpu-affinity", required_argument, NULL, ARG_CPU_AFFINITY },
517523
{}
518524
};
519525

@@ -1186,6 +1192,22 @@ static int parse_argv(int argc, char *argv[]) {
11861192
arg_settings_mask |= SETTING_OOM_SCORE_ADJUST;
11871193
break;
11881194

1195+
case ARG_CPU_AFFINITY: {
1196+
_cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
1197+
1198+
r = parse_cpu_set(optarg, &cpuset);
1199+
if (r < 0)
1200+
return log_error_errno(r, "Failed to parse CPU affinity mask: %s", optarg);
1201+
1202+
if (arg_cpuset)
1203+
CPU_FREE(arg_cpuset);
1204+
1205+
arg_cpuset = TAKE_PTR(cpuset);
1206+
arg_cpuset_ncpus = r;
1207+
arg_settings_mask |= SETTING_CPU_AFFINITY;
1208+
break;
1209+
}
1210+
11891211
case '?':
11901212
return -EINVAL;
11911213

@@ -2476,6 +2498,10 @@ static int inner_child(
24762498
return log_error_errno(r, "Failed to adjust OOM score: %m");
24772499
}
24782500

2501+
if (arg_cpuset)
2502+
if (sched_setaffinity(0, CPU_ALLOC_SIZE(arg_cpuset_ncpus), arg_cpuset) < 0)
2503+
return log_error_errno(errno, "Failed to set CPU affinity: %m");
2504+
24792505
r = drop_capabilities();
24802506
if (r < 0)
24812507
return log_error_errno(r, "drop_capabilities() failed: %m");
@@ -3397,6 +3423,19 @@ static int load_settings(void) {
33973423
}
33983424
}
33993425

3426+
if ((arg_settings_mask & SETTING_CPU_AFFINITY) == 0 &&
3427+
settings->cpuset) {
3428+
3429+
if (!arg_settings_trusted)
3430+
log_warning("Ignoring CPUAffinity= setting, file '%s' is not trusted.", p);
3431+
else {
3432+
if (arg_cpuset)
3433+
CPU_FREE(arg_cpuset);
3434+
arg_cpuset = TAKE_PTR(settings->cpuset);
3435+
arg_cpuset_ncpus = settings->cpuset_ncpus;
3436+
}
3437+
}
3438+
34003439
return 0;
34013440
}
34023441

@@ -4375,6 +4414,7 @@ int main(int argc, char *argv[]) {
43754414
expose_port_free_all(arg_expose_ports);
43764415
free(arg_root_hash);
43774416
rlimit_free_all(arg_rlimit);
4417+
arg_cpuset = cpu_set_mfree(arg_cpuset);
43784418

43794419
return r < 0 ? EXIT_FAILURE : ret;
43804420
}

0 commit comments

Comments
 (0)