aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSerge E. Hallyn <serue@us.ibm.com>2008-04-29 04:00:14 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-29 11:06:10 -0400
commit29486df325e1fe6e1764afcb19e3370804c2b002 (patch)
treed69a96bb829940f3ae5171fde481edb20a9e468a
parent28fd5dfc12bde391981dfdcf20755952b6e916af (diff)
cgroups: introduce cft->read_seq()
Introduce a read_seq() helper in cftype, which uses seq_file to print out lists. Use it in the devices cgroup. Also split devices.allow into two files, so now devices.deny and devices.allow are the ones to use to manipulate the whitelist, while devices.list outputs the cgroup's current whitelist. Signed-off-by: Serge E. Hallyn <serue@us.ibm.com> Acked-by: Paul Menage <menage@google.com> Cc: Balbir Singh <balbir@in.ibm.com> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/cgroup.h6
-rw-r--r--kernel/cgroup.c15
-rw-r--r--security/device_cgroup.c74
3 files changed, 38 insertions, 57 deletions
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index d58a958444ab..095248082b7e 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -226,6 +226,12 @@ struct cftype {
226 */ 226 */
227 int (*read_map) (struct cgroup *cont, struct cftype *cft, 227 int (*read_map) (struct cgroup *cont, struct cftype *cft,
228 struct cgroup_map_cb *cb); 228 struct cgroup_map_cb *cb);
229 /*
230 * read_seq_string() is used for outputting a simple sequence
231 * using seqfile.
232 */
233 int (*read_seq_string) (struct cgroup *cont, struct cftype *cft,
234 struct seq_file *m);
229 235
230 ssize_t (*write) (struct cgroup *cgrp, struct cftype *cft, 236 ssize_t (*write) (struct cgroup *cgrp, struct cftype *cft,
231 struct file *file, 237 struct file *file,
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index aeceb8868981..abc433772e5a 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -1549,11 +1549,14 @@ static int cgroup_seqfile_show(struct seq_file *m, void *arg)
1549{ 1549{
1550 struct cgroup_seqfile_state *state = m->private; 1550 struct cgroup_seqfile_state *state = m->private;
1551 struct cftype *cft = state->cft; 1551 struct cftype *cft = state->cft;
1552 struct cgroup_map_cb cb = { 1552 if (cft->read_map) {
1553 .fill = cgroup_map_add, 1553 struct cgroup_map_cb cb = {
1554 .state = m, 1554 .fill = cgroup_map_add,
1555 }; 1555 .state = m,
1556 return cft->read_map(state->cgroup, cft, &cb); 1556 };
1557 return cft->read_map(state->cgroup, cft, &cb);
1558 }
1559 return cft->read_seq_string(state->cgroup, cft, m);
1557} 1560}
1558 1561
1559int cgroup_seqfile_release(struct inode *inode, struct file *file) 1562int cgroup_seqfile_release(struct inode *inode, struct file *file)
@@ -1581,7 +1584,7 @@ static int cgroup_file_open(struct inode *inode, struct file *file)
1581 cft = __d_cft(file->f_dentry); 1584 cft = __d_cft(file->f_dentry);
1582 if (!cft) 1585 if (!cft)
1583 return -ENODEV; 1586 return -ENODEV;
1584 if (cft->read_map) { 1587 if (cft->read_map || cft->read_seq_string) {
1585 struct cgroup_seqfile_state *state = 1588 struct cgroup_seqfile_state *state =
1586 kzalloc(sizeof(*state), GFP_USER); 1589 kzalloc(sizeof(*state), GFP_USER);
1587 if (!state) 1590 if (!state)
diff --git a/security/device_cgroup.c b/security/device_cgroup.c
index 4237b19e8fb3..4ea583689eec 100644
--- a/security/device_cgroup.c
+++ b/security/device_cgroup.c
@@ -9,6 +9,7 @@
9#include <linux/ctype.h> 9#include <linux/ctype.h>
10#include <linux/list.h> 10#include <linux/list.h>
11#include <linux/uaccess.h> 11#include <linux/uaccess.h>
12#include <linux/seq_file.h>
12 13
13#define ACC_MKNOD 1 14#define ACC_MKNOD 1
14#define ACC_READ 2 15#define ACC_READ 2
@@ -201,11 +202,15 @@ static void devcgroup_destroy(struct cgroup_subsys *ss,
201 202
202#define DEVCG_ALLOW 1 203#define DEVCG_ALLOW 1
203#define DEVCG_DENY 2 204#define DEVCG_DENY 2
205#define DEVCG_LIST 3
206
207#define MAJMINLEN 10
208#define ACCLEN 4
204 209
205static void set_access(char *acc, short access) 210static void set_access(char *acc, short access)
206{ 211{
207 int idx = 0; 212 int idx = 0;
208 memset(acc, 0, 4); 213 memset(acc, 0, ACCLEN);
209 if (access & ACC_READ) 214 if (access & ACC_READ)
210 acc[idx++] = 'r'; 215 acc[idx++] = 'r';
211 if (access & ACC_WRITE) 216 if (access & ACC_WRITE)
@@ -225,70 +230,33 @@ static char type_to_char(short type)
225 return 'X'; 230 return 'X';
226} 231}
227 232
228static void set_majmin(char *str, int len, unsigned m) 233static void set_majmin(char *str, unsigned m)
229{ 234{
230 memset(str, 0, len); 235 memset(str, 0, MAJMINLEN);
231 if (m == ~0) 236 if (m == ~0)
232 sprintf(str, "*"); 237 sprintf(str, "*");
233 else 238 else
234 snprintf(str, len, "%d", m); 239 snprintf(str, MAJMINLEN, "%d", m);
235} 240}
236 241
237static char *print_whitelist(struct dev_cgroup *devcgroup, int *len) 242static int devcgroup_seq_read(struct cgroup *cgroup, struct cftype *cft,
243 struct seq_file *m)
238{ 244{
239 char *buf, *s, acc[4]; 245 struct dev_cgroup *devcgroup = cgroup_to_devcgroup(cgroup);
240 struct dev_whitelist_item *wh; 246 struct dev_whitelist_item *wh;
241 int ret; 247 char maj[MAJMINLEN], min[MAJMINLEN], acc[ACCLEN];
242 int count = 0;
243 char maj[10], min[10];
244
245 buf = kmalloc(4096, GFP_KERNEL);
246 if (!buf)
247 return ERR_PTR(-ENOMEM);
248 s = buf;
249 *s = '\0';
250 *len = 0;
251 248
252 spin_lock(&devcgroup->lock); 249 spin_lock(&devcgroup->lock);
253 list_for_each_entry(wh, &devcgroup->whitelist, list) { 250 list_for_each_entry(wh, &devcgroup->whitelist, list) {
254 set_access(acc, wh->access); 251 set_access(acc, wh->access);
255 set_majmin(maj, 10, wh->major); 252 set_majmin(maj, wh->major);
256 set_majmin(min, 10, wh->minor); 253 set_majmin(min, wh->minor);
257 ret = snprintf(s, 4095-(s-buf), "%c %s:%s %s\n", 254 seq_printf(m, "%c %s:%s %s\n", type_to_char(wh->type),
258 type_to_char(wh->type), maj, min, acc); 255 maj, min, acc);
259 if (s+ret >= buf+4095) {
260 kfree(buf);
261 buf = ERR_PTR(-ENOMEM);
262 break;
263 }
264 s += ret;
265 *len += ret;
266 count++;
267 } 256 }
268 spin_unlock(&devcgroup->lock); 257 spin_unlock(&devcgroup->lock);
269 258
270 return buf; 259 return 0;
271}
272
273static ssize_t devcgroup_access_read(struct cgroup *cgroup,
274 struct cftype *cft, struct file *file,
275 char __user *userbuf, size_t nbytes, loff_t *ppos)
276{
277 struct dev_cgroup *devcgroup = cgroup_to_devcgroup(cgroup);
278 int filetype = cft->private;
279 char *buffer;
280 int uninitialized_var(len);
281 int retval;
282
283 if (filetype != DEVCG_ALLOW)
284 return -EINVAL;
285 buffer = print_whitelist(devcgroup, &len);
286 if (IS_ERR(buffer))
287 return PTR_ERR(buffer);
288
289 retval = simple_read_from_buffer(userbuf, nbytes, ppos, buffer, len);
290 kfree(buffer);
291 return retval;
292} 260}
293 261
294/* 262/*
@@ -501,7 +469,6 @@ out1:
501static struct cftype dev_cgroup_files[] = { 469static struct cftype dev_cgroup_files[] = {
502 { 470 {
503 .name = "allow", 471 .name = "allow",
504 .read = devcgroup_access_read,
505 .write = devcgroup_access_write, 472 .write = devcgroup_access_write,
506 .private = DEVCG_ALLOW, 473 .private = DEVCG_ALLOW,
507 }, 474 },
@@ -510,6 +477,11 @@ static struct cftype dev_cgroup_files[] = {
510 .write = devcgroup_access_write, 477 .write = devcgroup_access_write,
511 .private = DEVCG_DENY, 478 .private = DEVCG_DENY,
512 }, 479 },
480 {
481 .name = "list",
482 .read_seq_string = devcgroup_seq_read,
483 .private = DEVCG_LIST,
484 },
513}; 485};
514 486
515static int devcgroup_populate(struct cgroup_subsys *ss, 487static int devcgroup_populate(struct cgroup_subsys *ss,