From d84c42924cc7621b2aec9f67f6b8d4785fa40da9 Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Fri, 25 Jul 2008 19:58:14 +0000 Subject: [PATCH] Add support for a new login capability, cpumask which allows login sessions to be pinned to cpus by login class. --- lib/libutil/login.conf.5 | 9 ++++ lib/libutil/login_cap.h | 3 +- lib/libutil/login_class.3 | 14 +++++ lib/libutil/login_class.c | 107 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 132 insertions(+), 1 deletion(-) diff --git a/lib/libutil/login.conf.5 b/lib/libutil/login.conf.5 index b4c96f298767..863aa0616908 100644 --- a/lib/libutil/login.conf.5 +++ b/lib/libutil/login.conf.5 @@ -203,6 +203,15 @@ The maximum and current limits may be specified individually by appending a .It Sy "Name Type Notes Description .It "charset string Set $MM_CHARSET environment variable to the specified value. +.It "cpumask string List of cpus to bind the user to. +The syntax is the same as for the +.Fl l +argument of +.Xr cpuset 1 or the word +.Ql default . +If set to +.Ql default +no action is taken. .It "hushlogin bool false Same as having a ~/.hushlogin file. .It "ignorenologin bool false Login not prevented by nologin. .It "ftp-chroot bool false Limit FTP access with diff --git a/lib/libutil/login_cap.h b/lib/libutil/login_cap.h index a7cb4c67e8f0..c98e7fd0b473 100644 --- a/lib/libutil/login_cap.h +++ b/lib/libutil/login_cap.h @@ -48,7 +48,8 @@ #define LOGIN_SETUSER 0x0040 /* set user (via setuid) */ #define LOGIN_SETENV 0x0080 /* set user environment */ #define LOGIN_SETMAC 0x0100 /* set user default MAC label */ -#define LOGIN_SETALL 0x01ff /* set everything */ +#define LOGIN_SETCPUMASK 0x0200 /* set user cpumask */ +#define LOGIN_SETALL 0x03ff /* set everything */ #define BI_AUTH "authorize" /* accepted authentication */ #define BI_REJECT "reject" /* rejected authentication */ diff --git a/lib/libutil/login_class.3 b/lib/libutil/login_class.3 index ca5b2cebf972..c91f9a9ef68e 100644 --- a/lib/libutil/login_class.3 +++ b/lib/libutil/login_class.3 @@ -155,6 +155,18 @@ capability "setenv=var1 val1,var2 val2..,varN valN". Set the MAC label for the current process to the label specified in system login class database. .Pp +.It LOGIN_SETCPUMASK +Create a new +.Xr cpuset 2 +and set the cpu affinity to the specified mask. +The string may contain a comma separated list of numbers and/or number +ranges as handled by the +.Xr cpuset 1 +utility or the case-insensitive string +.Ql default . +If the string is +.Ql default +no action will be taken. .It LOGIN_SETALL Enables all of the above settings. .El @@ -186,6 +198,8 @@ or resources, a message is reported to .Xr syslog 3 , with LOG_ERR priority and directed to the currently active facility. .Sh SEE ALSO +.Xr cpuset 1 , +.Xr cpuset 2 , .Xr setgid 2 , .Xr setlogin 2 , .Xr setuid 2 , diff --git a/lib/libutil/login_class.c b/lib/libutil/login_class.c index 39f114f2d49f..c18d46af9878 100644 --- a/lib/libutil/login_class.c +++ b/lib/libutil/login_class.c @@ -26,9 +26,11 @@ __FBSDID("$FreeBSD$"); #include +#include #include #include #include +#include #include #include #include @@ -239,6 +241,108 @@ setclassenvironment(login_cap_t *lc, const struct passwd * pwd, int paths) } +static int +list2cpuset(const char *list, cpuset_t *mask) +{ + enum { NONE, NUM, DASH } state; + int lastnum; + int curnum; + const char *l; + + state = NONE; + curnum = lastnum = 0; + for (l = list; *l != '\0';) { + if (isdigit(*l)) { + curnum = atoi(l); + if (curnum > CPU_SETSIZE) + errx(EXIT_FAILURE, + "Only %d cpus supported", CPU_SETSIZE); + while (isdigit(*l)) + l++; + switch (state) { + case NONE: + lastnum = curnum; + state = NUM; + break; + case DASH: + for (; lastnum <= curnum; lastnum++) + CPU_SET(lastnum, mask); + state = NONE; + break; + case NUM: + default: + return (0); + } + continue; + } + switch (*l) { + case ',': + switch (state) { + case NONE: + break; + case NUM: + CPU_SET(curnum, mask); + state = NONE; + break; + case DASH: + return (0); + break; + } + break; + case '-': + if (state != NUM) + return (0); + state = DASH; + break; + default: + return (0); + } + l++; + } + switch (state) { + case NONE: + break; + case NUM: + CPU_SET(curnum, mask); + break; + case DASH: + return (0); + } + return 1; +} + + +void +setclasscpumask(login_cap_t *lc) +{ + const char *maskstr; + cpuset_t maskset; + cpusetid_t setid; + + maskstr = login_getcapstr(lc, "cpumask", NULL, NULL); + CPU_ZERO(&maskset); + if (maskstr == NULL) + return; + if (strcasecmp("default", maskstr) == 0) + return; + if (!list2cpuset(maskstr, &maskset)) { + syslog(LOG_WARNING, + "list2cpuset(%s) invalid mask specification", maskstr); + return; + } + + if (cpuset(&setid) != 0) { + syslog(LOG_ERR, "cpuset(): %s", strerror(errno)); + return; + } + + if (cpuset_setaffinity(CPU_LEVEL_CPUSET, CPU_WHICH_PID, -1, + sizeof(maskset), &maskset) != 0) + syslog(LOG_ERR, "cpuset_setaffinity(%s): %s", maskstr, + strerror(errno)); +} + + /* * setclasscontext() * @@ -289,6 +393,9 @@ setlogincontext(login_cap_t *lc, const struct passwd *pwd, /* Set environment */ if (flags & LOGIN_SETENV) setclassenvironment(lc, pwd, 0); + /* Set cpu affinity */ + if (flags & LOGIN_SETCPUMASK) + setclasscpumask(lc); } return mymask; }