diff options
author | Tejun Heo <tj@kernel.org> | 2013-12-05 12:28:04 -0500 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2013-12-05 12:28:04 -0500 |
commit | 6612f05b88fa309c91a345690411217959bb2486 (patch) | |
tree | b124fd822b3b2bdb169b341cff1118a586d782a7 /kernel/cgroup.c | |
parent | 2da8ca822d49c8b8781800ad155aaa00e7bb5f1a (diff) |
cgroup: unify pidlist and other file handling
In preparation of conversion to kernfs, cgroup file handling is
updated so that it can be easily mapped to kernfs. With the previous
changes, the difference between pidlist and other files are very
small. Both are served by seq_file in a pretty standard way with the
only difference being !pidlist files use single_open().
This patch adds cftype->seq_start(), ->seq_next and ->seq_stop() and
implements the matching cgroup_seqfile_start/next/stop() which either
emulates single_open() behavior or invokes cftype->seq_*() operations
if specified. This allows using single seq_operations for both
pidlist and other files and makes cgroup_pidlist_operations and
cgorup_pidlist_open() no longer necessary. As cgroup_pidlist_open()
was the only user of cftype->open(), the method is dropped together.
This brings cftype file interface very close to kernfs interface and
mapping shouldn't be too difficult. Once converted to kernfs, most of
the plumbing code including cgroup_seqfile_*() will be removed as
kernfs provides those facilities.
This patch does not introduce any behavior changes.
v2: Refreshed on top of the updated "cgroup: introduce struct
cgroup_pidlist_open_file".
v3: Refreshed on top of the updated "cgroup: attach cgroup_open_file
to all cgroup files".
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Li Zefan <lizefan@huawei.com>
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r-- | kernel/cgroup.c | 112 |
1 files changed, 63 insertions, 49 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index c45e63328a0a..f9ae38a95af2 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -2286,6 +2286,45 @@ out_free: | |||
2286 | * supports string->u64 maps, but can be extended in future. | 2286 | * supports string->u64 maps, but can be extended in future. |
2287 | */ | 2287 | */ |
2288 | 2288 | ||
2289 | static void *cgroup_seqfile_start(struct seq_file *seq, loff_t *ppos) | ||
2290 | { | ||
2291 | struct cftype *cft = seq_cft(seq); | ||
2292 | |||
2293 | if (cft->seq_start) { | ||
2294 | return cft->seq_start(seq, ppos); | ||
2295 | } else { | ||
2296 | /* | ||
2297 | * The same behavior and code as single_open(). Returns | ||
2298 | * !NULL if pos is at the beginning; otherwise, NULL. | ||
2299 | */ | ||
2300 | return NULL + !*ppos; | ||
2301 | } | ||
2302 | } | ||
2303 | |||
2304 | static void *cgroup_seqfile_next(struct seq_file *seq, void *v, loff_t *ppos) | ||
2305 | { | ||
2306 | struct cftype *cft = seq_cft(seq); | ||
2307 | |||
2308 | if (cft->seq_next) { | ||
2309 | return cft->seq_next(seq, v, ppos); | ||
2310 | } else { | ||
2311 | /* | ||
2312 | * The same behavior and code as single_open(), always | ||
2313 | * terminate after the initial read. | ||
2314 | */ | ||
2315 | ++*ppos; | ||
2316 | return NULL; | ||
2317 | } | ||
2318 | } | ||
2319 | |||
2320 | static void cgroup_seqfile_stop(struct seq_file *seq, void *v) | ||
2321 | { | ||
2322 | struct cftype *cft = seq_cft(seq); | ||
2323 | |||
2324 | if (cft->seq_stop) | ||
2325 | cft->seq_stop(seq, v); | ||
2326 | } | ||
2327 | |||
2289 | static int cgroup_seqfile_show(struct seq_file *m, void *arg) | 2328 | static int cgroup_seqfile_show(struct seq_file *m, void *arg) |
2290 | { | 2329 | { |
2291 | struct cftype *cft = seq_cft(m); | 2330 | struct cftype *cft = seq_cft(m); |
@@ -2303,12 +2342,20 @@ static int cgroup_seqfile_show(struct seq_file *m, void *arg) | |||
2303 | return 0; | 2342 | return 0; |
2304 | } | 2343 | } |
2305 | 2344 | ||
2345 | static struct seq_operations cgroup_seq_operations = { | ||
2346 | .start = cgroup_seqfile_start, | ||
2347 | .next = cgroup_seqfile_next, | ||
2348 | .stop = cgroup_seqfile_stop, | ||
2349 | .show = cgroup_seqfile_show, | ||
2350 | }; | ||
2351 | |||
2306 | static int cgroup_file_open(struct inode *inode, struct file *file) | 2352 | static int cgroup_file_open(struct inode *inode, struct file *file) |
2307 | { | 2353 | { |
2308 | struct cfent *cfe = __d_cfe(file->f_dentry); | 2354 | struct cfent *cfe = __d_cfe(file->f_dentry); |
2309 | struct cftype *cft = __d_cft(file->f_dentry); | 2355 | struct cftype *cft = __d_cft(file->f_dentry); |
2310 | struct cgroup *cgrp = __d_cgrp(cfe->dentry->d_parent); | 2356 | struct cgroup *cgrp = __d_cgrp(cfe->dentry->d_parent); |
2311 | struct cgroup_subsys_state *css; | 2357 | struct cgroup_subsys_state *css; |
2358 | struct cgroup_open_file *of; | ||
2312 | int err; | 2359 | int err; |
2313 | 2360 | ||
2314 | err = generic_file_open(inode, file); | 2361 | err = generic_file_open(inode, file); |
@@ -2338,24 +2385,16 @@ static int cgroup_file_open(struct inode *inode, struct file *file) | |||
2338 | WARN_ON_ONCE(cfe->css && cfe->css != css); | 2385 | WARN_ON_ONCE(cfe->css && cfe->css != css); |
2339 | cfe->css = css; | 2386 | cfe->css = css; |
2340 | 2387 | ||
2341 | if (cft->open) { | 2388 | of = __seq_open_private(file, &cgroup_seq_operations, |
2342 | err = cft->open(inode, file); | 2389 | sizeof(struct cgroup_open_file)); |
2343 | } else { | 2390 | if (of) { |
2344 | struct cgroup_open_file *of; | 2391 | of->cfe = cfe; |
2345 | 2392 | return 0; | |
2346 | err = -ENOMEM; | ||
2347 | of = kzalloc(sizeof(*of), GFP_KERNEL); | ||
2348 | if (of) { | ||
2349 | of->cfe = cfe; | ||
2350 | err = single_open(file, cgroup_seqfile_show, of); | ||
2351 | if (err) | ||
2352 | kfree(of); | ||
2353 | } | ||
2354 | } | 2393 | } |
2355 | 2394 | ||
2356 | if (css->ss && err) | 2395 | if (css->ss) |
2357 | css_put(css); | 2396 | css_put(css); |
2358 | return err; | 2397 | return -ENOMEM; |
2359 | } | 2398 | } |
2360 | 2399 | ||
2361 | static int cgroup_file_release(struct inode *inode, struct file *file) | 2400 | static int cgroup_file_release(struct inode *inode, struct file *file) |
@@ -2365,8 +2404,7 @@ static int cgroup_file_release(struct inode *inode, struct file *file) | |||
2365 | 2404 | ||
2366 | if (css->ss) | 2405 | if (css->ss) |
2367 | css_put(css); | 2406 | css_put(css); |
2368 | kfree(((struct seq_file *)file->private_data)->private); | 2407 | return seq_release_private(inode, file); |
2369 | return single_release(inode, file); | ||
2370 | } | 2408 | } |
2371 | 2409 | ||
2372 | /* | 2410 | /* |
@@ -3777,36 +3815,6 @@ static const struct seq_operations cgroup_pidlist_seq_operations = { | |||
3777 | .show = cgroup_pidlist_show, | 3815 | .show = cgroup_pidlist_show, |
3778 | }; | 3816 | }; |
3779 | 3817 | ||
3780 | static const struct file_operations cgroup_pidlist_operations = { | ||
3781 | .read = seq_read, | ||
3782 | .llseek = seq_lseek, | ||
3783 | .write = cgroup_file_write, | ||
3784 | .release = seq_release_private, | ||
3785 | }; | ||
3786 | |||
3787 | /* | ||
3788 | * The following functions handle opens on a file that displays a pidlist | ||
3789 | * (tasks or procs). Prepare an array of the process/thread IDs of whoever's | ||
3790 | * in the cgroup. | ||
3791 | */ | ||
3792 | /* helper function for the two below it */ | ||
3793 | static int cgroup_pidlist_open(struct inode *unused, struct file *file) | ||
3794 | { | ||
3795 | struct cfent *cfe = __d_cfe(file->f_dentry); | ||
3796 | struct cgroup_open_file *of; | ||
3797 | |||
3798 | /* configure file information */ | ||
3799 | file->f_op = &cgroup_pidlist_operations; | ||
3800 | |||
3801 | of = __seq_open_private(file, &cgroup_pidlist_seq_operations, | ||
3802 | sizeof(*of)); | ||
3803 | if (!of) | ||
3804 | return -ENOMEM; | ||
3805 | |||
3806 | of->cfe = cfe; | ||
3807 | return 0; | ||
3808 | } | ||
3809 | |||
3810 | static u64 cgroup_read_notify_on_release(struct cgroup_subsys_state *css, | 3818 | static u64 cgroup_read_notify_on_release(struct cgroup_subsys_state *css, |
3811 | struct cftype *cft) | 3819 | struct cftype *cft) |
3812 | { | 3820 | { |
@@ -3860,7 +3868,10 @@ static int cgroup_clone_children_write(struct cgroup_subsys_state *css, | |||
3860 | static struct cftype cgroup_base_files[] = { | 3868 | static struct cftype cgroup_base_files[] = { |
3861 | { | 3869 | { |
3862 | .name = "cgroup.procs", | 3870 | .name = "cgroup.procs", |
3863 | .open = cgroup_pidlist_open, | 3871 | .seq_start = cgroup_pidlist_start, |
3872 | .seq_next = cgroup_pidlist_next, | ||
3873 | .seq_stop = cgroup_pidlist_stop, | ||
3874 | .seq_show = cgroup_pidlist_show, | ||
3864 | .private = CGROUP_FILE_PROCS, | 3875 | .private = CGROUP_FILE_PROCS, |
3865 | .write_u64 = cgroup_procs_write, | 3876 | .write_u64 = cgroup_procs_write, |
3866 | .mode = S_IRUGO | S_IWUSR, | 3877 | .mode = S_IRUGO | S_IWUSR, |
@@ -3885,7 +3896,10 @@ static struct cftype cgroup_base_files[] = { | |||
3885 | { | 3896 | { |
3886 | .name = "tasks", | 3897 | .name = "tasks", |
3887 | .flags = CFTYPE_INSANE, /* use "procs" instead */ | 3898 | .flags = CFTYPE_INSANE, /* use "procs" instead */ |
3888 | .open = cgroup_pidlist_open, | 3899 | .seq_start = cgroup_pidlist_start, |
3900 | .seq_next = cgroup_pidlist_next, | ||
3901 | .seq_stop = cgroup_pidlist_stop, | ||
3902 | .seq_show = cgroup_pidlist_show, | ||
3889 | .private = CGROUP_FILE_TASKS, | 3903 | .private = CGROUP_FILE_TASKS, |
3890 | .write_u64 = cgroup_tasks_write, | 3904 | .write_u64 = cgroup_tasks_write, |
3891 | .mode = S_IRUGO | S_IWUSR, | 3905 | .mode = S_IRUGO | S_IWUSR, |