[systemd-devel] [PATCH] systemd: add RDTCacheReservation= option to support CAT (Cache Allocation Technology)
Marcelo Tosatti
mtosatti at redhat.com
Fri Jan 6 13:59:03 UTC 2017
Cache Allocation Technology is a feature on selected recent Intel Xeon
processors which allows control over L3 cache allocation.
Kernel support has been merged to the upstream kernel, via a filesystem
resctrlfs.
On top of that, a userspace utility, resctrltool has been written
to facilitate writing applications and using the filesystem
interface (see the rationale at
http://www.mail-archive.com/linux-kernel@vger.kernel.org/msg1300792.html).
This patch adds a new option to systemd, RDTCacheReservation,
to allow configuration of CAT via resctrltool.
See the first hunk of the patch for a description of the option.
Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
Index: systemd/man/systemd.exec.xml
===================================================================
--- systemd.orig/man/systemd.exec.xml
+++ systemd/man/systemd.exec.xml
@@ -233,6 +233,31 @@
</varlistentry>
<varlistentry>
+ <term><varname>RDTCacheReservation=</varname></term>
+
+ <listitem><para>Creates a L3 CAT reservation in resctrlfs
+ for the executed processes. Takes a ";" separated list of
+ tuples (optionally triples) containing type,size and
+ optionally cacheid:
+ type=type,size=size,cacheid=id;
+ type=type,size=size,cacheid=id;...
+
+ Where:
+
+ type is one of: both, data, code.
+ size is size in kbytes.
+ cacheid (optional) is the cacheid for
+ the reservation.
+
+ Rules for the parameters:
+ * type=code must be paired with type=data entry.
+
+ See the output of resctrltool for more details.
+
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><varname>IOSchedulingClass=</varname></term>
<listitem><para>Sets the I/O scheduling class for executed
Index: systemd/src/basic/exit-status.c
===================================================================
--- systemd.orig/src/basic/exit-status.c
+++ systemd/src/basic/exit-status.c
@@ -62,6 +62,9 @@ const char* exit_status_to_string(int st
case EXIT_OOM_ADJUST:
return "OOM_ADJUST";
+ case EXIT_RDT_CACHE_RESERVATION:
+ return "RDT_CACHE_RESERVATION";
+
case EXIT_SIGNAL_MASK:
return "SIGNAL_MASK";
Index: systemd/src/basic/exit-status.h
===================================================================
--- systemd.orig/src/basic/exit-status.h
+++ systemd/src/basic/exit-status.h
@@ -83,6 +83,7 @@ enum {
EXIT_CHOWN,
EXIT_SMACK_PROCESS_LABEL,
EXIT_KEYRING,
+ EXIT_RDT_CACHE_RESERVATION,
};
typedef enum ExitStatusLevel {
Index: systemd/src/core/dbus-execute.c
===================================================================
--- systemd.orig/src/core/dbus-execute.c
+++ systemd/src/core/dbus-execute.c
@@ -119,6 +119,36 @@ static int property_get_oom_score_adjust
return sd_bus_message_append(reply, "i", n);
}
+static int property_get_rdt_cache_reservation(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ ExecContext *c = userdata;
+ int r;
+ int i;
+
+ assert(bus);
+ assert(reply);
+ assert(c);
+
+ r = sd_bus_message_open_container(reply, 'a', "s");
+ if (r < 0)
+ return r;
+
+ for (i = 0; i < c->argmidx; i++) {
+ r = sd_bus_message_append(reply, "s", c->argm[i]);
+ if (r < 0)
+ return r;
+ }
+
+ return sd_bus_message_close_container(reply);
+}
+
static int property_get_nice(
sd_bus *bus,
const char *path,
@@ -759,6 +789,7 @@ const sd_bus_vtable bus_exec_vtable[] =
SD_BUS_PROPERTY("WorkingDirectory", "s", property_get_working_directory, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RDTCacheReservation", "as", property_get_rdt_cache_reservation, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("IOScheduling", "i", property_get_ioprio, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CPUSchedulingPolicy", "i", property_get_cpu_sched_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST),
@@ -921,6 +952,90 @@ int bus_property_get_exec_command_list(
return sd_bus_message_close_container(reply);
}
+static char* convert_rdt_back(char *argm[], int argmidx)
+{
+ int i, ret;
+ char *buf, *str;
+ int size = 0;
+ int printcomma = 0;
+ int printsemicolon = 0;
+ int localmode = 0;
+
+ for (i=0; i < argmidx; i++) {
+ /* ',', ';', '=' */
+ size += strlen(argm[i]) + 3;
+ }
+
+ buf = malloc(size);
+ if (buf == NULL)
+ return NULL;
+ memset(buf, 0, size);
+
+ str = buf;
+
+ /* cache-id specified */
+ for (i=0; i < argmidx; i++) {
+ if (strlen(argm[i]) == 10) {
+ if (strcmp(argm[i], "--cache-id") == 0)
+ localmode = 1;
+ }
+ }
+
+ for (i=0; i<argmidx; i++) {
+ char *cur = argm[i];
+
+ if (strlen(cur) == 0)
+ return buf;
+
+ if (strlen(cur) == 6) {
+ if (strcmp(cur, "--type") == 0) {
+ ret = sprintf(str, "type=");
+ str = str + ret;
+ printcomma = 1;
+ continue;
+ }
+
+ if (strcmp(cur, "--size") == 0) {
+ ret = sprintf(str, "size=");
+ str = str + ret;
+ if (localmode == 1)
+ printcomma = 1;
+ else
+ printsemicolon = 1;
+
+ continue;
+ }
+ }
+
+ if (strlen(cur) == 10) {
+ if (strcmp(cur, "--cache-id") == 0) {
+ ret = sprintf(str, "cache-id=");
+ str = str + ret;
+ printsemicolon = 1;
+ continue;
+ }
+ }
+
+ ret = sprintf(str, "%s", cur);
+ str = str + ret;
+
+ if (i != argmidx - 1) {
+ if (printsemicolon) {
+ ret = sprintf(str, ";");
+ str = str + 1;
+ } else if (printcomma) {
+ ret = sprintf(str, ",");
+ str = str + 1;
+ }
+
+ printcomma = 0;
+ printsemicolon = 0;
+ }
+ }
+
+ return buf;
+}
+
int bus_exec_context_set_transient_property(
Unit *u,
ExecContext *c,
@@ -1377,6 +1492,46 @@ int bus_exec_context_set_transient_prope
}
return 1;
+ } else if (streq(name, "RDTCacheReservation")) {
+
+ r = sd_bus_message_enter_container(message, 'a', "s");
+ if (r < 0)
+ return r;
+
+ while ((r = sd_bus_message_enter_container(message, 'r', "s")) > 0) {
+ const char *str;
+
+ r = sd_bus_message_read(message, "s", &str);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK)
+ c->argm[c->argmidx++] = strdup(str);
+
+ r = sd_bus_message_exit_container(message);
+ if (r < 0)
+ return r;
+ }
+
+ if (mode != UNIT_CHECK) {
+ char *conv;
+
+ conv = convert_rdt_back(c->argm, c->argmidx);
+ if (conv == NULL) {
+ return sd_bus_error_setf(error,
+ SD_BUS_ERROR_NO_MEMORY,
+ "out of memory for rdt string convertion");
+ }
+
+ unit_write_drop_in_private_format(u, mode, name, "RDTCacheReservation=%s", conv);
+ free(conv);
+ }
+
+ r = sd_bus_message_exit_container(message);
+ if (r < 0)
+ return r;
+
+ return 1;
} else if (streq(name, "EnvironmentFiles")) {
Index: systemd/src/core/execute.c
===================================================================
--- systemd.orig/src/core/execute.c
+++ systemd/src/core/execute.c
@@ -36,6 +36,10 @@
#include <sys/un.h>
#include <unistd.h>
#include <utmpx.h>
+#include <fcntl.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/wait.h>
#ifdef HAVE_PAM
#include <security/pam_appl.h>
@@ -2201,6 +2205,161 @@ static int apply_working_directory(const
return 0;
}
+
+static int fork_exec_resctrltool(Unit *u, char *argv[])
+{
+ int outpipe[2];
+ int errpipe[2];
+ pid_t cpid;
+
+ pipe(outpipe);
+ pipe(errpipe);
+ cpid = fork();
+
+ if(cpid == 0) {
+ int r;
+
+ dup2(errpipe[1], STDERR_FILENO);
+ dup2(outpipe[1], STDOUT_FILENO);
+
+ r = execve(argv[0], argv, NULL);
+ if (r == -1) {
+ log_open();
+ log_unit_error_errno(u, r, "Failed to execve resctrltool, ignoring: %m");
+ log_close();
+ return -errno;
+ }
+ } else {
+ char buffer[100];
+ fd_set fdset;
+ int count;
+ int ret;
+ int nfds;
+ int status = 0;
+ int retst;
+
+ ret = waitpid(cpid, &status, 0);
+ if (ret == -1) {
+ log_open();
+ log_unit_error_errno(u, ret, "Failed to waitpid resctrltool, ignoring: %m");
+ log_close();
+ return -errno;
+ }
+
+ if (!WIFEXITED(status)) {
+ log_open();
+ log_unit_error_errno(u, ret, "resctrltool exits abnormally, ignoring: %m");
+ log_close();
+ return -1;
+ } else {
+ retst = WEXITSTATUS(status);
+
+ if (retst == 0) {
+ return 0;
+ }
+ }
+
+ /*
+ * error, read stderr and stdout and log.
+ */
+
+ FD_ZERO(&fdset);
+ FD_SET(outpipe[0], &fdset);
+ FD_SET(errpipe[0], &fdset);
+
+ if (outpipe[0] > errpipe[0])
+ nfds = outpipe[0] + 1;
+ else
+ nfds = errpipe[0] + 1;
+
+ ret = select(nfds, &fdset, NULL, NULL, NULL);
+ if (ret == -1) {
+ log_open();
+ log_unit_error_errno(u, ret, "select error, ignoring RDTCacheReservation: %m");
+ log_close();
+ return -1;
+ }
+
+ if (FD_ISSET(outpipe[0], &fdset)) {
+ count = read(outpipe[0], buffer, sizeof(buffer)-1);
+ if (count >= 0) {
+ buffer[count] = 0;
+ log_open();
+ log_unit_error(u, "resctrltool stdout: %s", buffer);
+ log_close();
+ } else {
+ log_open();
+ log_unit_error(u, "resctrltool io error\n");
+ log_close();
+ }
+ }
+
+ if (FD_ISSET(errpipe[0], &fdset)) {
+ count = read(errpipe[0], buffer, sizeof(buffer)-1);
+ if (count >= 0) {
+ buffer[count] = 0;
+ log_open();
+ log_unit_error(u, "resctrltool stderr: %s", buffer);
+ log_close();
+ } else {
+ log_open();
+ log_unit_error(u, "resctrltool io error\n");
+ log_close();
+ }
+ }
+
+ return retst;
+ }
+
+ return -1;
+}
+
+static int setup_rdt_cat(Unit *u, const ExecContext *c, pid_t pid)
+{
+ int ret, i;
+ const char *arg[5];
+ char pidstr[100];
+ char *name = u->id;
+ const char *largm[ARGMSIZE + 4];
+
+ sprintf(pidstr, "%d", pid);
+
+ arg[0] = "/usr/bin/resctrltool";
+ arg[1] = "delete";
+ arg[2] = name;
+ arg[3] = 0;
+
+ ret = fork_exec_resctrltool(u, (char **)arg);
+ /* we want to ignore 'reservation does not exist'
+ * errors, so skip error checking entirely.
+ * any other errors will be caught when trying
+ * to execute create below
+ */
+
+ memset(largm, 0, sizeof(largm));
+ largm[0] = "/usr/bin/resctrltool";
+ largm[1] = "create";
+ largm[2] = "--name";
+ largm[3] = name;
+ for (i = 0; i < c->argmidx; i++)
+ largm[i+4] = c->argm[i];
+
+ ret = fork_exec_resctrltool(u, (char **)largm);
+ if (ret)
+ return ret;
+
+ arg[0] = "/usr/bin/resctrltool";
+ arg[1] = "assign";
+ arg[2] = pidstr;
+ arg[3] = name;
+ arg[4] = 0;
+ ret = fork_exec_resctrltool(u, (char **)arg);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
static int setup_keyring(Unit *u, const ExecParameters *p, uid_t uid, gid_t gid) {
key_serial_t keyring;
@@ -2572,6 +2731,15 @@ static int exec_child(
}
}
+ if (context->rdt_cache_reservation_set) {
+ r = setup_rdt_cat(unit, context, getpid());
+
+ if (r) {
+ *exit_status = EXIT_RDT_CACHE_RESERVATION;
+ return r;
+ }
+ }
+
if (context->nice_set)
if (setpriority(PRIO_PROCESS, 0, context->nice) < 0) {
*exit_status = EXIT_NICE;
Index: systemd/src/core/execute.h
===================================================================
--- systemd.orig/src/core/execute.h
+++ systemd/src/core/execute.h
@@ -100,6 +100,8 @@ struct ExecRuntime {
int netns_storage_socket[2];
};
+#define ARGMSIZE 100
+
struct ExecContext {
char **environment;
char **environment_files;
@@ -218,6 +220,11 @@ struct ExecContext {
bool nice_set:1;
bool ioprio_set:1;
bool cpu_sched_set:1;
+ bool rdt_cache_reservation_set:1;
+
+ /* Parameters for resctrltool */
+ char *argm[ARGMSIZE];
+ int argmidx;
};
static inline bool exec_context_restrict_namespaces_set(const ExecContext *c) {
Index: systemd/src/core/load-fragment-gperf.gperf.m4
===================================================================
--- systemd.orig/src/core/load-fragment-gperf.gperf.m4
+++ systemd/src/core/load-fragment-gperf.gperf.m4
@@ -24,6 +24,7 @@ $1.Group, config_
$1.SupplementaryGroups, config_parse_user_group_strv, 0, offsetof($1, exec_context.supplementary_groups)
$1.Nice, config_parse_exec_nice, 0, offsetof($1, exec_context)
$1.OOMScoreAdjust, config_parse_exec_oom_score_adjust, 0, offsetof($1, exec_context)
+$1.RDTCacheReservation, config_parse_rdt_cache_reservation, 0, offsetof($1, exec_context)
$1.IOSchedulingClass, config_parse_exec_io_class, 0, offsetof($1, exec_context)
$1.IOSchedulingPriority, config_parse_exec_io_priority, 0, offsetof($1, exec_context)
$1.CPUSchedulingPolicy, config_parse_exec_cpu_sched_policy, 0, offsetof($1, exec_context)
Index: systemd/src/core/load-fragment.c
===================================================================
--- systemd.orig/src/core/load-fragment.c
+++ systemd/src/core/load-fragment.c
@@ -567,6 +567,230 @@ int config_parse_exec_oom_score_adjust(c
return 0;
}
+#define STATE_NEXT_TYPE 0
+#define STATE_NEXT_SIZE 1
+#define STATE_NEXT_CACHEID_OR_END 2
+
+static void free_argm(ExecContext *c)
+{
+ int i;
+
+ for (i=0; i < c->argmidx; i++) {
+ free(c->argm[i]);
+ c->argm[i] = NULL;
+ }
+ c->argmidx = 0;
+}
+
+int config_parse_rdt_cache_reservation(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) {
+
+ ExecContext *c = data;
+ int curstate = STATE_NEXT_TYPE;
+ char *buf = (char *)rvalue;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if (isempty(rvalue)) {
+ /* An empty assignment resets the list */
+ free_argm(c);
+ return 0;
+ }
+
+ do {
+ if (c->argmidx > ARGMSIZE - 3) {
+ free_argm(c);
+ log_syntax(unit, LOG_ERR, filename, line, ENOMEM,
+ "argmidx overflow, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ switch (curstate) {
+ case STATE_NEXT_TYPE: {
+ char *string, *buf2;
+
+ buf = strstr(buf, "type=");
+ if (buf == NULL) {
+ free_argm(c);
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "type= not found when expected, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ buf2 = strstr(buf, ",");
+ if (buf2 == NULL) {
+ free_argm(c);
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ ", not found when parsing type, ignoring: %s", rvalue);
+ return 0;
+ }
+ if (strlen(buf) <= 5) {
+ free_argm(c);
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "invalid type, ignoring: %s", rvalue);
+ return 0;
+ }
+ /* skip type= */
+ buf = buf + 5;
+ if (strlen(buf) < 4) {
+ free_argm(c);
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "invalid type, ignoring: %s", rvalue);
+ return 0;
+ }
+ string = strndup(buf, 4);
+ if (string == NULL) {
+ free_argm(c);
+ log_syntax(unit, LOG_ERR, filename, line, ENOMEM,
+ "enomem for strndup, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ c->argm[c->argmidx++] = strdup("--type");
+ c->argm[c->argmidx++] = string;
+
+ /* skip {code,data,both}, */
+ buf = buf + 5;
+ curstate = STATE_NEXT_SIZE;
+ break;
+ }
+ case STATE_NEXT_SIZE: {
+ char *string, *buf2, *commabuf, *dotcommabuf;
+ int len, skip = 0;
+
+ buf = strstr(buf, "size=");
+ if (buf == NULL) {
+ free_argm(c);
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "size= not found when expected, ignoring: %s", rvalue);
+ return 0;
+ }
+ if (strlen(buf) <= 5) {
+ free_argm(c);
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "invalid size, ignoring: %s", rvalue);
+ return 0;
+ }
+ /* skip size= */
+ buf = buf + 5;
+
+ commabuf = strstr(buf, ",");
+ dotcommabuf = strstr(buf, ";");
+
+ buf2 = NULL;
+
+ /* the end, neither , or ; follow */
+ if (commabuf == NULL && dotcommabuf == NULL) {
+ buf2 = buf + strlen(buf);
+ skip = 0;
+ /* only ',': cache-id must follow */
+ } else if (commabuf && dotcommabuf == NULL) {
+ buf2 = commabuf;
+ skip = 1;
+ /* trailing ';' at the end */
+ } else if (commabuf == NULL && dotcommabuf) {
+ buf2 = dotcommabuf;
+ skip = 1;
+ } else if (commabuf && dotcommabuf) {
+ if (commabuf > dotcommabuf)
+ buf2 = dotcommabuf;
+ else
+ buf2 = commabuf;
+ skip = 1;
+ }
+ len = buf2 - buf;
+ string = strndup(buf, len);
+ if (string == NULL) {
+ free_argm(c);
+ log_syntax(unit, LOG_ERR, filename, line, ENOMEM,
+ "enomem for strndup, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ c->argm[c->argmidx++] = strdup("--size");
+ c->argm[c->argmidx++] = string;
+ curstate = STATE_NEXT_CACHEID_OR_END;
+
+ buf = buf2;
+ buf = buf + skip;
+ break;
+ }
+ case STATE_NEXT_CACHEID_OR_END: {
+ char *buf2, *string, *dotcommabuf;
+ int len, skip = 0;
+
+ if (strlen(buf) < 4)
+ break;
+
+ if (strncmp(buf, "type", 4) == 0) {
+ curstate = STATE_NEXT_TYPE;
+ break;
+ }
+
+ buf = strstr(buf, "cache-id=");
+ if (buf == NULL) {
+ free_argm(c);
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "cache-id= not found when expected, ignoring: %s", rvalue);
+ return 0;
+ }
+ if (strlen(buf) <= 9) {
+ free_argm(c);
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "invalid cache-id=, ignoring: %s", rvalue);
+ return 0;
+ }
+ /* skip cache-id= */
+ buf = buf + 9;
+
+ dotcommabuf = strstr(buf, ";");
+ /* the end */
+ if (dotcommabuf == NULL) {
+ buf2 = buf + strlen(buf);
+ skip = 0;
+ } else {
+ buf2 = dotcommabuf;
+ skip = 1;
+ }
+ len = buf2 - buf;
+ string = strndup(buf, len);
+ if (string == NULL) {
+ free_argm(c);
+ log_syntax(unit, LOG_ERR, filename, line, ENOMEM,
+ "enomem for strndup, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ c->argm[c->argmidx++] = strdup("--cache-id");
+ c->argm[c->argmidx++] = string;
+
+ buf = buf + skip;
+ curstate = STATE_NEXT_TYPE;
+ break;
+ }
+ default:
+ break;
+ }
+ } while (strlen(buf) > 4);
+
+ c->argm[c->argmidx] = 0;
+
+ c->rdt_cache_reservation_set = true;
+
+ return 0;
+}
+
int config_parse_exec(
const char *unit,
const char *filename,
@@ -4551,6 +4775,8 @@ void unit_dump_config_items(FILE *f) {
{ config_parse_job_mode, "MODE" },
{ config_parse_job_mode_isolate, "BOOLEAN" },
{ config_parse_personality, "PERSONALITY" },
+ { config_parse_rdt_cache_reservation, "RDTCACHERESERVATION" },
+
};
const char *prev = NULL;
Index: systemd/src/core/load-fragment.h
===================================================================
--- systemd.orig/src/core/load-fragment.h
+++ systemd/src/core/load-fragment.h
@@ -40,6 +40,7 @@ int config_parse_socket_protocol(const c
int config_parse_socket_bind(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);
int config_parse_exec_nice(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);
int config_parse_exec_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);
+int config_parse_rdt_cache_reservation(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);
int config_parse_exec(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);
int config_parse_service_timeout(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);
int config_parse_service_type(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);
Index: systemd/src/shared/bus-unit-util.c
===================================================================
--- systemd.orig/src/shared/bus-unit-util.c
+++ systemd/src/shared/bus-unit-util.c
@@ -61,6 +61,7 @@ int bus_parse_unit_info(sd_bus_message *
&u->job_path);
}
+
int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) {
const char *eq, *field;
UnitDependency dep;
@@ -470,6 +471,199 @@ int bus_append_unit_property_assignment(
}
r = sd_bus_message_append(m, "v", "i", oa);
+ } else if (streq(field, "RDTCacheReservation")) {
+ int argmidx = 0;
+#define ARGMSIZE 100
+#define STATE_NEXT_TYPE 0
+#define STATE_NEXT_SIZE 1
+#define STATE_NEXT_CACHEID_OR_END 2
+ int curstate = STATE_NEXT_TYPE;
+ char *buf = (char *)eq;
+
+ r = sd_bus_message_open_container(m, 'v', "as");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_open_container(m, 'a', "s");
+ if (r < 0)
+ return r;
+
+ do {
+ if (argmidx > ARGMSIZE - 3) {
+ log_error("argmidx overflow");
+ return -EINVAL;
+ }
+
+ switch (curstate) {
+ case STATE_NEXT_TYPE: {
+ char *string, *buf2;
+
+ buf = strstr(buf, "type=");
+ if (buf == NULL) {
+ log_error("type= not found when expected");
+ return 0;
+ }
+
+ buf2 = strstr(buf, ",");
+ if (buf2 == NULL) {
+ log_error(", not found when parsing type");
+ return 0;
+ }
+ if (strlen(buf) <= 5) {
+ log_error("invalid type");
+ return 0;
+ }
+
+ /* skip type= */
+ buf = buf + 5;
+ string = strndup(buf, 4);
+ if (string == NULL) {
+ log_error("enomem for strndup");
+ return 0;
+ }
+
+ r = sd_bus_message_append_basic(m, 's', "--type");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_basic(m, 's', string);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ free(string);
+
+ /* skip {code,data,both}, */
+ buf = buf + 5;
+ curstate = STATE_NEXT_SIZE;
+ break;
+ }
+
+ case STATE_NEXT_SIZE: {
+ char *string, *buf2, *commabuf, *dotcommabuf;
+ int len, skip = 0;
+
+ buf = strstr(buf, "size=");
+ if (buf == NULL) {
+ log_error("size= not found when expected");
+ return 0;
+ }
+ if (strlen(buf) <= 5) {
+ log_error("invalid type");
+ return 0;
+ }
+ /* skip size= */
+ buf = buf + 5;
+
+ commabuf = strstr(buf, ",");
+ dotcommabuf = strstr(buf, ";");
+
+ /* the end, neither , or ; follow */
+ if (commabuf == NULL && dotcommabuf == NULL) {
+ buf2 = buf + strlen(buf);
+ skip = 0;
+ /* only ',': cache-id must follow */
+ } else if (commabuf && dotcommabuf == NULL) {
+ buf2 = commabuf;
+ skip = 1;
+ /* trailing ';' at the end */
+ } else if (commabuf == NULL && dotcommabuf) {
+ buf2 = dotcommabuf;
+ skip = 1;
+ } else if (commabuf && dotcommabuf) {
+ if (commabuf > dotcommabuf)
+ buf2 = dotcommabuf;
+ else
+ buf2 = commabuf;
+ skip = 1;
+ }
+ len = buf2 - buf;
+ string = strndup(buf, len);
+ if (string == NULL) {
+ log_error("enomem for strndup");
+ return 0;
+ }
+
+ r = sd_bus_message_append_basic(m, 's', "--size");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_basic(m, 's', string);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ free(string);
+ curstate = STATE_NEXT_CACHEID_OR_END;
+
+ buf = buf2;
+ buf = buf + skip;
+ break;
+ }
+ case STATE_NEXT_CACHEID_OR_END: {
+ char *buf2, *string, *dotcommabuf;
+ int len, skip = 0;
+
+ if (strlen(buf) < 4)
+ break;
+ if (strncmp(buf, "type", 4) == 0) {
+ curstate = STATE_NEXT_TYPE;
+ break;
+ }
+
+ buf = strstr(buf, "cache-id=");
+ if (buf == NULL) {
+ log_error("cache-id= not found when expected");
+ return 0;
+ }
+ if (strlen(buf) <= 9) {
+ log_error("invalid cache-id=");
+ return 0;
+ }
+ /* skip cache-id= */
+ buf = buf + 9;
+
+ dotcommabuf = strstr(buf, ";");
+ /* the end */
+ if (dotcommabuf == NULL) {
+ buf2 = buf + strlen(buf);
+ skip = 0;
+ } else {
+ buf2 = dotcommabuf;
+ buf2 = buf2 + 1;
+ skip = 0;
+ }
+ len = buf2 - buf;
+ string = strndup(buf, len);
+ if (string == NULL) {
+ log_error("enomem for strndup");
+ return 0;
+ }
+
+ r = sd_bus_message_append_basic(m, 's', "--cache-id");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_basic(m, 's', string);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ free(string);
+
+ buf = buf + skip;
+ curstate = STATE_NEXT_TYPE;
+ break;
+ }
+ default:
+ break;
+ }
+ } while (strlen(buf) > 4);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0) {
+ return bus_log_create_error(r);
+ }
+
+ r = sd_bus_message_close_container(m);
+
} else if (STR_IN_SET(field, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories",
"ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths")) {
const char *p;
More information about the systemd-devel
mailing list