Blame SOURCES/libcgroup-0.41-api.c-support-for-setting-multiline-values-in-contro.patch

4b3140
From 691430206f1104b752b0e52386f317e639137788 Mon Sep 17 00:00:00 2001
4b3140
From: Jan Chaloupka <jchaloup@redhat.com>
4b3140
Date: Mon, 15 Sep 2014 13:29:39 +0200
4b3140
Subject: [PATCH] api.c: support for setting multiline values in control files
4b3140
4b3140
As of now, libcgroup does not support multiline values setting from configuration files. i.e. values in a form:
4b3140
4b3140
net_prio.ifpriomap="lo 7
4b3140
eth0 66
4b3140
eth1 5
4b3140
eth2 4
4b3140
eth3 3";
4b3140
4b3140
Thus, setting of more network interfaces can not be done from configuration file. Or
4b3140
4b3140
devices.allow="a *:* w
4b3140
c 8:* r";
4b3140
4b3140
thus setting list of allow devices can not be set as well. The only way is to set it from userspace, e.g.:
4b3140
# echo "lo 7" > /sys/fs/cgroup/net_prio/testGroup/net_prio.ifpriomap
4b3140
# echo "eth 0" > /sys/fs/cgroup/net_prio/testGroup/net_prio.ifpriomap
4b3140
# echo "eth 1" > /sys/fs/cgroup/net_prio/testGroup/net_prio.ifpriomap
4b3140
# echo "eth 2" > /sys/fs/cgroup/net_prio/testGroup/net_prio.ifpriomap
4b3140
# echo "eth 3" > /sys/fs/cgroup/net_prio/testGroup/net_prio.ifpriomap
4b3140
4b3140
This patch allows setting of multiline variables.
4b3140
4b3140
How this support works:
4b3140
Multiline value is broken in lines and each line is set by write (man 2 write) syscall (without bufferring).
4b3140
This implies change of fopen with open, fclose with close.
4b3140
There is no control on multiline value, thus "eth0\n  \t\n" can be set. However, setting
4b3140
of "  \t" will fail as write command returns -1. Thus administrator has to set correct
4b3140
multiline values.
4b3140
4b3140
Tested on virtual machine with fedora and rhel with network interface lo, eth0-eth3. Configuration file:
4b3140
4b3140
# cat /etc/cgconfig.conf
4b3140
group testGroup {
4b3140
        net_prio {
4b3140
                net_prio.ifpriomap="lo 7
4b3140
eth0    66
4b3140
eth1 5
4b3140
eth2 4
4b3140
eth3 3";
4b3140
        }
4b3140
}
4b3140
4b3140
net_prio has to be created before:
4b3140
# modprobe netprio_cgroup
4b3140
# mkdir /sys/fs/cgroup/net_prio
4b3140
# mount -t cgroup -onet_prio none /sys/fs/cgroup/net_prio
4b3140
4b3140
Changelog:
4b3140
	test of success of strdup call
4b3140
	free str_val before return (str_val is changing in while cycle,
4b3140
		thus str_start_val points to the start of str_val before while)
4b3140
4b3140
Signed-off-by: Jan Chaloupka <jchaloup@redhat.com>
4b3140
---
4b3140
 src/api.c | 50 ++++++++++++++++++++++++++++++++++++++++++++------
4b3140
 1 file changed, 44 insertions(+), 6 deletions(-)
4b3140
4b3140
diff --git a/src/api.c b/src/api.c
4b3140
index 5751b8f..d6c9d3a 100644
4b3140
--- a/src/api.c
4b3140
+++ b/src/api.c
4b3140
@@ -1495,13 +1495,18 @@ static int cg_create_control_group(const char *path)
4b3140
  */
4b3140
 static int cg_set_control_value(char *path, const char *val)
4b3140
 {
4b3140
-	FILE *control_file = NULL;
4b3140
+	int ctl_file;
4b3140
+	char *str_val;
4b3140
+	char *str_val_start;
4b3140
+	char *pos;
4b3140
+	size_t len;
4b3140
+
4b3140
 	if (!cg_test_mounted_fs())
4b3140
 		return ECGROUPNOTMOUNTED;
4b3140
 
4b3140
-	control_file = fopen(path, "r+e");
4b3140
+	ctl_file = open(path, O_RDWR | O_CLOEXEC);
4b3140
 
4b3140
-	if (!control_file) {
4b3140
+	if (ctl_file == -1) {
4b3140
 		if (errno == EPERM) {
4b3140
 			/*
4b3140
 			 * We need to set the correct error value, does the
4b3140
@@ -1512,6 +1517,7 @@ static int cg_set_control_value(char *path, const char *val)
4b3140
 			 */
4b3140
 			char *path_dir_end;
4b3140
 			char *tasks_path;
4b3140
+			FILE *control_file;
4b3140
 
4b3140
 			path_dir_end = strrchr(path, '/');
4b3140
 			if (path_dir_end == NULL)
4b3140
@@ -1543,15 +1549,47 @@ static int cg_set_control_value(char *path, const char *val)
4b3140
 		return ECGROUPVALUENOTEXIST;
4b3140
 	}
4b3140
 
4b3140
-	if (fprintf(control_file, "%s", val) < 0) {
4b3140
+	/* Split the multiline value into lines. */
4b3140
+	/* One line is a special case of multiline value. */
4b3140
+	str_val = strdup(val);
4b3140
+	if (str_val == NULL) {
4b3140
 		last_errno = errno;
4b3140
-		fclose(control_file);
4b3140
+		close(ctl_file);
4b3140
 		return ECGOTHER;
4b3140
 	}
4b3140
-	if (fclose(control_file) < 0) {
4b3140
+
4b3140
+	str_val_start = str_val;
4b3140
+	pos = str_val;
4b3140
+
4b3140
+	do {
4b3140
+		str_val = pos;
4b3140
+		pos = strchr(str_val, '\n');
4b3140
+
4b3140
+		if (pos) {
4b3140
+			*pos = '\0';
4b3140
+			++pos;
4b3140
+		}
4b3140
+
4b3140
+		len = strlen(str_val);
4b3140
+		if (len > 0) {
4b3140
+			if (write(ctl_file, str_val, len) == -1) {
4b3140
+				last_errno = errno;
4b3140
+				free(str_val_start);
4b3140
+				close(ctl_file);
4b3140
+				return ECGOTHER;
4b3140
+			}
4b3140
+		} else
4b3140
+			cgroup_warn("Warning: skipping empty line for %s\n",
4b3140
+				path);
4b3140
+	} while(pos);
4b3140
+
4b3140
+	if (close(ctl_file)) {
4b3140
 		last_errno = errno;
4b3140
+		free(str_val_start);
4b3140
 		return ECGOTHER;
4b3140
 	}
4b3140
+
4b3140
+	free(str_val_start);
4b3140
 	return 0;
4b3140
 }
4b3140
 
4b3140
-- 
4b3140
1.9.3
4b3140