Commit f92523e3 authored by Paul Menage's avatar Paul Menage Committed by Linus Torvalds

cgroup files: convert devcgroup_access_write() into a cgroup write_string() handler

This patch converts devcgroup_access_write() from a raw file handler
into a handler for the cgroup write_string() method. This allows some
boilerplate copying/locking/checking to be removed and simplifies the
cleanup path, since these functions are performed by the cgroups
framework before calling the handler.
Signed-off-by: default avatarPaul Menage <menage@google.com>
Cc: Paul Jackson <pj@sgi.com>
Cc: Pavel Emelyanov <xemul@openvz.org>
Cc: Balbir Singh <balbir@in.ibm.com>
Acked-by: default avatarSerge Hallyn <serue@us.ibm.com>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent e3712395
...@@ -59,6 +59,11 @@ static inline struct dev_cgroup *cgroup_to_devcgroup(struct cgroup *cgroup) ...@@ -59,6 +59,11 @@ static inline struct dev_cgroup *cgroup_to_devcgroup(struct cgroup *cgroup)
return css_to_devcgroup(cgroup_subsys_state(cgroup, devices_subsys_id)); return css_to_devcgroup(cgroup_subsys_state(cgroup, devices_subsys_id));
} }
static inline struct dev_cgroup *task_devcgroup(struct task_struct *task)
{
return css_to_devcgroup(task_subsys_state(task, devices_subsys_id));
}
struct cgroup_subsys devices_subsys; struct cgroup_subsys devices_subsys;
static int devcgroup_can_attach(struct cgroup_subsys *ss, static int devcgroup_can_attach(struct cgroup_subsys *ss,
...@@ -312,10 +317,10 @@ static int may_access_whitelist(struct dev_cgroup *c, ...@@ -312,10 +317,10 @@ static int may_access_whitelist(struct dev_cgroup *c,
* when adding a new allow rule to a device whitelist, the rule * when adding a new allow rule to a device whitelist, the rule
* must be allowed in the parent device * must be allowed in the parent device
*/ */
static int parent_has_perm(struct cgroup *childcg, static int parent_has_perm(struct dev_cgroup *childcg,
struct dev_whitelist_item *wh) struct dev_whitelist_item *wh)
{ {
struct cgroup *pcg = childcg->parent; struct cgroup *pcg = childcg->css.cgroup->parent;
struct dev_cgroup *parent; struct dev_cgroup *parent;
int ret; int ret;
...@@ -341,39 +346,18 @@ static int parent_has_perm(struct cgroup *childcg, ...@@ -341,39 +346,18 @@ static int parent_has_perm(struct cgroup *childcg,
* new access is only allowed if you're in the top-level cgroup, or your * new access is only allowed if you're in the top-level cgroup, or your
* parent cgroup has the access you're asking for. * parent cgroup has the access you're asking for.
*/ */
static ssize_t devcgroup_access_write(struct cgroup *cgroup, struct cftype *cft, static int devcgroup_update_access(struct dev_cgroup *devcgroup,
struct file *file, const char __user *userbuf, int filetype, const char *buffer)
size_t nbytes, loff_t *ppos)
{ {
struct cgroup *cur_cgroup; struct dev_cgroup *cur_devcgroup;
struct dev_cgroup *devcgroup, *cur_devcgroup; const char *b;
int filetype = cft->private;
char *buffer, *b;
int retval = 0, count; int retval = 0, count;
struct dev_whitelist_item wh; struct dev_whitelist_item wh;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
devcgroup = cgroup_to_devcgroup(cgroup); cur_devcgroup = task_devcgroup(current);
cur_cgroup = task_cgroup(current, devices_subsys.subsys_id);
cur_devcgroup = cgroup_to_devcgroup(cur_cgroup);
buffer = kmalloc(nbytes+1, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
if (copy_from_user(buffer, userbuf, nbytes)) {
retval = -EFAULT;
goto out1;
}
buffer[nbytes] = 0; /* nul-terminate */
cgroup_lock();
if (cgroup_is_removed(cgroup)) {
retval = -ENODEV;
goto out2;
}
memset(&wh, 0, sizeof(wh)); memset(&wh, 0, sizeof(wh));
b = buffer; b = buffer;
...@@ -392,14 +376,11 @@ static ssize_t devcgroup_access_write(struct cgroup *cgroup, struct cftype *cft, ...@@ -392,14 +376,11 @@ static ssize_t devcgroup_access_write(struct cgroup *cgroup, struct cftype *cft,
wh.type = DEV_CHAR; wh.type = DEV_CHAR;
break; break;
default: default:
retval = -EINVAL; return -EINVAL;
goto out2;
} }
b++; b++;
if (!isspace(*b)) { if (!isspace(*b))
retval = -EINVAL; return -EINVAL;
goto out2;
}
b++; b++;
if (*b == '*') { if (*b == '*') {
wh.major = ~0; wh.major = ~0;
...@@ -411,13 +392,10 @@ static ssize_t devcgroup_access_write(struct cgroup *cgroup, struct cftype *cft, ...@@ -411,13 +392,10 @@ static ssize_t devcgroup_access_write(struct cgroup *cgroup, struct cftype *cft,
b++; b++;
} }
} else { } else {
retval = -EINVAL; return -EINVAL;
goto out2;
}
if (*b != ':') {
retval = -EINVAL;
goto out2;
} }
if (*b != ':')
return -EINVAL;
b++; b++;
/* read minor */ /* read minor */
...@@ -431,13 +409,10 @@ static ssize_t devcgroup_access_write(struct cgroup *cgroup, struct cftype *cft, ...@@ -431,13 +409,10 @@ static ssize_t devcgroup_access_write(struct cgroup *cgroup, struct cftype *cft,
b++; b++;
} }
} else { } else {
retval = -EINVAL; return -EINVAL;
goto out2;
}
if (!isspace(*b)) {
retval = -EINVAL;
goto out2;
} }
if (!isspace(*b))
return -EINVAL;
for (b++, count = 0; count < 3; count++, b++) { for (b++, count = 0; count < 3; count++, b++) {
switch (*b) { switch (*b) {
case 'r': case 'r':
...@@ -454,8 +429,7 @@ static ssize_t devcgroup_access_write(struct cgroup *cgroup, struct cftype *cft, ...@@ -454,8 +429,7 @@ static ssize_t devcgroup_access_write(struct cgroup *cgroup, struct cftype *cft,
count = 3; count = 3;
break; break;
default: default:
retval = -EINVAL; return -EINVAL;
goto out2;
} }
} }
...@@ -463,38 +437,39 @@ static ssize_t devcgroup_access_write(struct cgroup *cgroup, struct cftype *cft, ...@@ -463,38 +437,39 @@ static ssize_t devcgroup_access_write(struct cgroup *cgroup, struct cftype *cft,
retval = 0; retval = 0;
switch (filetype) { switch (filetype) {
case DEVCG_ALLOW: case DEVCG_ALLOW:
if (!parent_has_perm(cgroup, &wh)) if (!parent_has_perm(devcgroup, &wh))
retval = -EPERM; return -EPERM;
else return dev_whitelist_add(devcgroup, &wh);
retval = dev_whitelist_add(devcgroup, &wh);
break;
case DEVCG_DENY: case DEVCG_DENY:
dev_whitelist_rm(devcgroup, &wh); dev_whitelist_rm(devcgroup, &wh);
break; break;
default: default:
retval = -EINVAL; return -EINVAL;
goto out2;
} }
return 0;
}
if (retval == 0) static int devcgroup_access_write(struct cgroup *cgrp, struct cftype *cft,
retval = nbytes; const char *buffer)
{
out2: int retval;
if (!cgroup_lock_live_group(cgrp))
return -ENODEV;
retval = devcgroup_update_access(cgroup_to_devcgroup(cgrp),
cft->private, buffer);
cgroup_unlock(); cgroup_unlock();
out1:
kfree(buffer);
return retval; return retval;
} }
static struct cftype dev_cgroup_files[] = { static struct cftype dev_cgroup_files[] = {
{ {
.name = "allow", .name = "allow",
.write = devcgroup_access_write, .write_string = devcgroup_access_write,
.private = DEVCG_ALLOW, .private = DEVCG_ALLOW,
}, },
{ {
.name = "deny", .name = "deny",
.write = devcgroup_access_write, .write_string = devcgroup_access_write,
.private = DEVCG_DENY, .private = DEVCG_DENY,
}, },
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment