diff options
author | Li Zefan <lizefan@huawei.com> | 2013-07-31 21:51:47 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2013-08-01 09:29:41 -0400 |
commit | 876ede8b2b9880615be0de3ec7b8afd0a1786e76 (patch) | |
tree | b2c238a5939a6daf9f43b6eba1b1ceaf3dc2c372 | |
parent | e14880f7bb7e0dc0933af304998371dd543ceb40 (diff) |
cgroup: restructure the failure path in cgroup_write_event_control()
It uses a single label and checks the validity of each pointer. This
is err-prone, and actually we had a bug because one of the check was
insufficient.
Use multi lables as we do in other places.
v2:
- drop initializations of local variables.
Signed-off-by: Li Zefan <lizefan@huawei.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
-rw-r--r-- | kernel/cgroup.c | 39 |
1 files changed, 18 insertions, 21 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 3f6593333525..9f6dab22289e 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -3934,11 +3934,11 @@ static void cgroup_event_ptable_queue_proc(struct file *file, | |||
3934 | static int cgroup_write_event_control(struct cgroup *cgrp, struct cftype *cft, | 3934 | static int cgroup_write_event_control(struct cgroup *cgrp, struct cftype *cft, |
3935 | const char *buffer) | 3935 | const char *buffer) |
3936 | { | 3936 | { |
3937 | struct cgroup_event *event = NULL; | 3937 | struct cgroup_event *event; |
3938 | struct cgroup *cgrp_cfile; | 3938 | struct cgroup *cgrp_cfile; |
3939 | unsigned int efd, cfd; | 3939 | unsigned int efd, cfd; |
3940 | struct file *efile = NULL; | 3940 | struct file *efile; |
3941 | struct file *cfile = NULL; | 3941 | struct file *cfile; |
3942 | char *endp; | 3942 | char *endp; |
3943 | int ret; | 3943 | int ret; |
3944 | 3944 | ||
@@ -3964,31 +3964,31 @@ static int cgroup_write_event_control(struct cgroup *cgrp, struct cftype *cft, | |||
3964 | efile = eventfd_fget(efd); | 3964 | efile = eventfd_fget(efd); |
3965 | if (IS_ERR(efile)) { | 3965 | if (IS_ERR(efile)) { |
3966 | ret = PTR_ERR(efile); | 3966 | ret = PTR_ERR(efile); |
3967 | goto fail; | 3967 | goto out_kfree; |
3968 | } | 3968 | } |
3969 | 3969 | ||
3970 | event->eventfd = eventfd_ctx_fileget(efile); | 3970 | event->eventfd = eventfd_ctx_fileget(efile); |
3971 | if (IS_ERR(event->eventfd)) { | 3971 | if (IS_ERR(event->eventfd)) { |
3972 | ret = PTR_ERR(event->eventfd); | 3972 | ret = PTR_ERR(event->eventfd); |
3973 | goto fail; | 3973 | goto out_put_efile; |
3974 | } | 3974 | } |
3975 | 3975 | ||
3976 | cfile = fget(cfd); | 3976 | cfile = fget(cfd); |
3977 | if (!cfile) { | 3977 | if (!cfile) { |
3978 | ret = -EBADF; | 3978 | ret = -EBADF; |
3979 | goto fail; | 3979 | goto out_put_eventfd; |
3980 | } | 3980 | } |
3981 | 3981 | ||
3982 | /* the process need read permission on control file */ | 3982 | /* the process need read permission on control file */ |
3983 | /* AV: shouldn't we check that it's been opened for read instead? */ | 3983 | /* AV: shouldn't we check that it's been opened for read instead? */ |
3984 | ret = inode_permission(file_inode(cfile), MAY_READ); | 3984 | ret = inode_permission(file_inode(cfile), MAY_READ); |
3985 | if (ret < 0) | 3985 | if (ret < 0) |
3986 | goto fail; | 3986 | goto out_put_cfile; |
3987 | 3987 | ||
3988 | event->cft = __file_cft(cfile); | 3988 | event->cft = __file_cft(cfile); |
3989 | if (IS_ERR(event->cft)) { | 3989 | if (IS_ERR(event->cft)) { |
3990 | ret = PTR_ERR(event->cft); | 3990 | ret = PTR_ERR(event->cft); |
3991 | goto fail; | 3991 | goto out_put_cfile; |
3992 | } | 3992 | } |
3993 | 3993 | ||
3994 | /* | 3994 | /* |
@@ -3998,18 +3998,18 @@ static int cgroup_write_event_control(struct cgroup *cgrp, struct cftype *cft, | |||
3998 | cgrp_cfile = __d_cgrp(cfile->f_dentry->d_parent); | 3998 | cgrp_cfile = __d_cgrp(cfile->f_dentry->d_parent); |
3999 | if (cgrp_cfile != cgrp) { | 3999 | if (cgrp_cfile != cgrp) { |
4000 | ret = -EINVAL; | 4000 | ret = -EINVAL; |
4001 | goto fail; | 4001 | goto out_put_cfile; |
4002 | } | 4002 | } |
4003 | 4003 | ||
4004 | if (!event->cft->register_event || !event->cft->unregister_event) { | 4004 | if (!event->cft->register_event || !event->cft->unregister_event) { |
4005 | ret = -EINVAL; | 4005 | ret = -EINVAL; |
4006 | goto fail; | 4006 | goto out_put_cfile; |
4007 | } | 4007 | } |
4008 | 4008 | ||
4009 | ret = event->cft->register_event(cgrp, event->cft, | 4009 | ret = event->cft->register_event(cgrp, event->cft, |
4010 | event->eventfd, buffer); | 4010 | event->eventfd, buffer); |
4011 | if (ret) | 4011 | if (ret) |
4012 | goto fail; | 4012 | goto out_put_cfile; |
4013 | 4013 | ||
4014 | efile->f_op->poll(efile, &event->pt); | 4014 | efile->f_op->poll(efile, &event->pt); |
4015 | 4015 | ||
@@ -4029,16 +4029,13 @@ static int cgroup_write_event_control(struct cgroup *cgrp, struct cftype *cft, | |||
4029 | 4029 | ||
4030 | return 0; | 4030 | return 0; |
4031 | 4031 | ||
4032 | fail: | 4032 | out_put_cfile: |
4033 | if (cfile) | 4033 | fput(cfile); |
4034 | fput(cfile); | 4034 | out_put_eventfd: |
4035 | 4035 | eventfd_ctx_put(event->eventfd); | |
4036 | if (event && event->eventfd && !IS_ERR(event->eventfd)) | 4036 | out_put_efile: |
4037 | eventfd_ctx_put(event->eventfd); | 4037 | fput(efile); |
4038 | 4038 | out_kfree: | |
4039 | if (!IS_ERR_OR_NULL(efile)) | ||
4040 | fput(efile); | ||
4041 | |||
4042 | kfree(event); | 4039 | kfree(event); |
4043 | 4040 | ||
4044 | return ret; | 4041 | return ret; |