]>
Commit | Line | Data |
---|---|---|
9665627f AM |
1 | From 691430206f1104b752b0e52386f317e639137788 Mon Sep 17 00:00:00 2001 |
2 | From: Jan Chaloupka <jchaloup@redhat.com> | |
3 | Date: Mon, 15 Sep 2014 13:29:39 +0200 | |
4 | Subject: [PATCH] api.c: support for setting multiline values in control files | |
5 | ||
6 | As of now, libcgroup does not support multiline values setting from configuration files. i.e. values in a form: | |
7 | ||
8 | net_prio.ifpriomap="lo 7 | |
9 | eth0 66 | |
10 | eth1 5 | |
11 | eth2 4 | |
12 | eth3 3"; | |
13 | ||
14 | Thus, setting of more network interfaces can not be done from configuration file. Or | |
15 | ||
16 | devices.allow="a *:* w | |
17 | c 8:* r"; | |
18 | ||
19 | thus setting list of allow devices can not be set as well. The only way is to set it from userspace, e.g.: | |
20 | # echo "lo 7" > /sys/fs/cgroup/net_prio/testGroup/net_prio.ifpriomap | |
21 | # echo "eth 0" > /sys/fs/cgroup/net_prio/testGroup/net_prio.ifpriomap | |
22 | # echo "eth 1" > /sys/fs/cgroup/net_prio/testGroup/net_prio.ifpriomap | |
23 | # echo "eth 2" > /sys/fs/cgroup/net_prio/testGroup/net_prio.ifpriomap | |
24 | # echo "eth 3" > /sys/fs/cgroup/net_prio/testGroup/net_prio.ifpriomap | |
25 | ||
26 | This patch allows setting of multiline variables. | |
27 | ||
28 | How this support works: | |
29 | Multiline value is broken in lines and each line is set by write (man 2 write) syscall (without bufferring). | |
30 | This implies change of fopen with open, fclose with close. | |
31 | There is no control on multiline value, thus "eth0\n \t\n" can be set. However, setting | |
32 | of " \t" will fail as write command returns -1. Thus administrator has to set correct | |
33 | multiline values. | |
34 | ||
35 | Tested on virtual machine with fedora and rhel with network interface lo, eth0-eth3. Configuration file: | |
36 | ||
37 | # cat /etc/cgconfig.conf | |
38 | group testGroup { | |
39 | net_prio { | |
40 | net_prio.ifpriomap="lo 7 | |
41 | eth0 66 | |
42 | eth1 5 | |
43 | eth2 4 | |
44 | eth3 3"; | |
45 | } | |
46 | } | |
47 | ||
48 | net_prio has to be created before: | |
49 | # modprobe netprio_cgroup | |
50 | # mkdir /sys/fs/cgroup/net_prio | |
51 | # mount -t cgroup -onet_prio none /sys/fs/cgroup/net_prio | |
52 | ||
53 | Changelog: | |
54 | test of success of strdup call | |
55 | free str_val before return (str_val is changing in while cycle, | |
56 | thus str_start_val points to the start of str_val before while) | |
57 | ||
58 | Signed-off-by: Jan Chaloupka <jchaloup@redhat.com> | |
59 | --- | |
60 | src/api.c | 50 ++++++++++++++++++++++++++++++++++++++++++++------ | |
61 | 1 file changed, 44 insertions(+), 6 deletions(-) | |
62 | ||
63 | diff --git a/src/api.c b/src/api.c | |
64 | index 5751b8f..d6c9d3a 100644 | |
65 | --- a/src/api.c | |
66 | +++ b/src/api.c | |
67 | @@ -1495,13 +1495,18 @@ static int cg_create_control_group(const char *path) | |
68 | */ | |
69 | static int cg_set_control_value(char *path, const char *val) | |
70 | { | |
71 | - FILE *control_file = NULL; | |
72 | + int ctl_file; | |
73 | + char *str_val; | |
74 | + char *str_val_start; | |
75 | + char *pos; | |
76 | + size_t len; | |
77 | + | |
78 | if (!cg_test_mounted_fs()) | |
79 | return ECGROUPNOTMOUNTED; | |
80 | ||
81 | - control_file = fopen(path, "r+e"); | |
82 | + ctl_file = open(path, O_RDWR | O_CLOEXEC); | |
83 | ||
84 | - if (!control_file) { | |
85 | + if (ctl_file == -1) { | |
86 | if (errno == EPERM) { | |
87 | /* | |
88 | * We need to set the correct error value, does the | |
89 | @@ -1512,6 +1517,7 @@ static int cg_set_control_value(char *path, const char *val) | |
90 | */ | |
91 | char *path_dir_end; | |
92 | char *tasks_path; | |
93 | + FILE *control_file; | |
94 | ||
95 | path_dir_end = strrchr(path, '/'); | |
96 | if (path_dir_end == NULL) | |
97 | @@ -1543,15 +1549,47 @@ static int cg_set_control_value(char *path, const char *val) | |
98 | return ECGROUPVALUENOTEXIST; | |
99 | } | |
100 | ||
101 | - if (fprintf(control_file, "%s", val) < 0) { | |
102 | + /* Split the multiline value into lines. */ | |
103 | + /* One line is a special case of multiline value. */ | |
104 | + str_val = strdup(val); | |
105 | + if (str_val == NULL) { | |
106 | last_errno = errno; | |
107 | - fclose(control_file); | |
108 | + close(ctl_file); | |
109 | return ECGOTHER; | |
110 | } | |
111 | - if (fclose(control_file) < 0) { | |
112 | + | |
113 | + str_val_start = str_val; | |
114 | + pos = str_val; | |
115 | + | |
116 | + do { | |
117 | + str_val = pos; | |
118 | + pos = strchr(str_val, '\n'); | |
119 | + | |
120 | + if (pos) { | |
121 | + *pos = '\0'; | |
122 | + ++pos; | |
123 | + } | |
124 | + | |
125 | + len = strlen(str_val); | |
126 | + if (len > 0) { | |
127 | + if (write(ctl_file, str_val, len) == -1) { | |
128 | + last_errno = errno; | |
129 | + free(str_val_start); | |
130 | + close(ctl_file); | |
131 | + return ECGOTHER; | |
132 | + } | |
133 | + } else | |
134 | + cgroup_warn("Warning: skipping empty line for %s\n", | |
135 | + path); | |
136 | + } while(pos); | |
137 | + | |
138 | + if (close(ctl_file)) { | |
139 | last_errno = errno; | |
140 | + free(str_val_start); | |
141 | return ECGOTHER; | |
142 | } | |
143 | + | |
144 | + free(str_val_start); | |
145 | return 0; | |
146 | } | |
147 | ||
148 | -- | |
149 | 1.9.3 | |
150 |