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

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