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

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