aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/cgroup.h19
-rw-r--r--kernel/cgroup.c53
2 files changed, 71 insertions, 1 deletions
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 058371c5d36..0a3ab670dd2 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -166,6 +166,16 @@ struct css_set {
166 166
167}; 167};
168 168
169/*
170 * cgroup_map_cb is an abstract callback API for reporting map-valued
171 * control files
172 */
173
174struct cgroup_map_cb {
175 int (*fill)(struct cgroup_map_cb *cb, const char *key, u64 value);
176 void *state;
177};
178
169/* struct cftype: 179/* struct cftype:
170 * 180 *
171 * The files in the cgroup filesystem mostly have a very simple read/write 181 * The files in the cgroup filesystem mostly have a very simple read/write
@@ -194,6 +204,15 @@ struct cftype {
194 * single integer. Use it in place of read() 204 * single integer. Use it in place of read()
195 */ 205 */
196 u64 (*read_u64) (struct cgroup *cgrp, struct cftype *cft); 206 u64 (*read_u64) (struct cgroup *cgrp, struct cftype *cft);
207 /*
208 * read_map() is used for defining a map of key/value
209 * pairs. It should call cb->fill(cb, key, value) for each
210 * entry. The key/value pairs (and their ordering) should not
211 * change between reboots.
212 */
213 int (*read_map) (struct cgroup *cont, struct cftype *cft,
214 struct cgroup_map_cb *cb);
215
197 ssize_t (*write) (struct cgroup *cgrp, struct cftype *cft, 216 ssize_t (*write) (struct cgroup *cgrp, struct cftype *cft,
198 struct file *file, 217 struct file *file,
199 const char __user *buf, size_t nbytes, loff_t *ppos); 218 const char __user *buf, size_t nbytes, loff_t *ppos);
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 57afdde871a..693bcc03188 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -1492,6 +1492,46 @@ static ssize_t cgroup_file_read(struct file *file, char __user *buf,
1492 return -EINVAL; 1492 return -EINVAL;
1493} 1493}
1494 1494
1495/*
1496 * seqfile ops/methods for returning structured data. Currently just
1497 * supports string->u64 maps, but can be extended in future.
1498 */
1499
1500struct cgroup_seqfile_state {
1501 struct cftype *cft;
1502 struct cgroup *cgroup;
1503};
1504
1505static int cgroup_map_add(struct cgroup_map_cb *cb, const char *key, u64 value)
1506{
1507 struct seq_file *sf = cb->state;
1508 return seq_printf(sf, "%s %llu\n", key, (unsigned long long)value);
1509}
1510
1511static int cgroup_seqfile_show(struct seq_file *m, void *arg)
1512{
1513 struct cgroup_seqfile_state *state = m->private;
1514 struct cftype *cft = state->cft;
1515 struct cgroup_map_cb cb = {
1516 .fill = cgroup_map_add,
1517 .state = m,
1518 };
1519 return cft->read_map(state->cgroup, cft, &cb);
1520}
1521
1522int cgroup_seqfile_release(struct inode *inode, struct file *file)
1523{
1524 struct seq_file *seq = file->private_data;
1525 kfree(seq->private);
1526 return single_release(inode, file);
1527}
1528
1529static struct file_operations cgroup_seqfile_operations = {
1530 .read = seq_read,
1531 .llseek = seq_lseek,
1532 .release = cgroup_seqfile_release,
1533};
1534
1495static int cgroup_file_open(struct inode *inode, struct file *file) 1535static int cgroup_file_open(struct inode *inode, struct file *file)
1496{ 1536{
1497 int err; 1537 int err;
@@ -1504,7 +1544,18 @@ static int cgroup_file_open(struct inode *inode, struct file *file)
1504 cft = __d_cft(file->f_dentry); 1544 cft = __d_cft(file->f_dentry);
1505 if (!cft) 1545 if (!cft)
1506 return -ENODEV; 1546 return -ENODEV;
1507 if (cft->open) 1547 if (cft->read_map) {
1548 struct cgroup_seqfile_state *state =
1549 kzalloc(sizeof(*state), GFP_USER);
1550 if (!state)
1551 return -ENOMEM;
1552 state->cft = cft;
1553 state->cgroup = __d_cgrp(file->f_dentry->d_parent);
1554 file->f_op = &cgroup_seqfile_operations;
1555 err = single_open(file, cgroup_seqfile_show, state);
1556 if (err < 0)
1557 kfree(state);
1558 } else if (cft->open)
1508 err = cft->open(inode, file); 1559 err = cft->open(inode, file);
1509 else 1560 else
1510 err = 0; 1561 err = 0;