[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