* [PATCH, v5 0/2] Timer slack cgroup subsystem
@ 2011-02-07 9:46 Kirill A. Shutsemov
2011-02-07 9:46 ` [PATCH, v5 1/2] cgroups: export cgroup_iter_{start,next,end} Kirill A. Shutsemov
2011-02-07 9:46 ` [PATCH, v5 2/2] cgroups: introduce timer slack subsystem Kirill A. Shutsemov
0 siblings, 2 replies; 8+ messages in thread
From: Kirill A. Shutsemov @ 2011-02-07 9:46 UTC (permalink / raw)
To: Paul Menage, Li Zefan
Cc: containers, jacob.jun.pan, Arjan van de Ven, linux-kernel,
Matt Helsley, Kirill A. Shutemov
From: Kirill A. Shutemov <kirill@shutemov.name>
Changelog:
v5:
- -EBUSY on writing to timer_slack.min_slack_ns/max_slack_ns if a child has
wider min-max range
v4:
- hierarchy support
- drop dummy_timer_slack_check()
- workaround lockdep false (?) positive
- allow 0 as timer slack value
v3:
- rework interface
- s/EXPORT_SYMBOL/EXPORT_SYMBOL_GPL/
v2:
- fixed with CONFIG_CGROUP_TIMER_SLACK=y
v1:
- initial revision
Kirill A. Shutemov (2):
cgroups: export cgroup_iter_{start,next,end}
cgroups: introduce timer slack subsystem
include/linux/cgroup_subsys.h | 6 +
include/linux/init_task.h | 4 +-
init/Kconfig | 10 ++
kernel/Makefile | 1 +
kernel/cgroup.c | 3 +
kernel/cgroup_timer_slack.c | 281 +++++++++++++++++++++++++++++++++++++++++
kernel/sys.c | 19 ++-
7 files changed, 317 insertions(+), 7 deletions(-)
create mode 100644 kernel/cgroup_timer_slack.c
--
1.7.4
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH, v5 1/2] cgroups: export cgroup_iter_{start,next,end} 2011-02-07 9:46 [PATCH, v5 0/2] Timer slack cgroup subsystem Kirill A. Shutsemov @ 2011-02-07 9:46 ` Kirill A. Shutsemov 2011-02-07 9:57 ` Balbir Singh 2011-02-07 9:46 ` [PATCH, v5 2/2] cgroups: introduce timer slack subsystem Kirill A. Shutsemov 1 sibling, 1 reply; 8+ messages in thread From: Kirill A. Shutsemov @ 2011-02-07 9:46 UTC (permalink / raw) To: Paul Menage, Li Zefan Cc: containers, jacob.jun.pan, Arjan van de Ven, linux-kernel, Matt Helsley, Kirill A. Shutemov From: Kirill A. Shutemov <kirill@shutemov.name> Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name> Acked-by: Paul Menage <menage@google.com> --- kernel/cgroup.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index b24d702..8234daa 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -2443,6 +2443,7 @@ void cgroup_iter_start(struct cgroup *cgrp, struct cgroup_iter *it) it->cg_link = &cgrp->css_sets; cgroup_advance_iter(cgrp, it); } +EXPORT_SYMBOL_GPL(cgroup_iter_start); struct task_struct *cgroup_iter_next(struct cgroup *cgrp, struct cgroup_iter *it) @@ -2467,11 +2468,13 @@ struct task_struct *cgroup_iter_next(struct cgroup *cgrp, } return res; } +EXPORT_SYMBOL_GPL(cgroup_iter_next); void cgroup_iter_end(struct cgroup *cgrp, struct cgroup_iter *it) { read_unlock(&css_set_lock); } +EXPORT_SYMBOL_GPL(cgroup_iter_end); static inline int started_after_time(struct task_struct *t1, struct timespec *time, -- 1.7.4 ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH, v5 1/2] cgroups: export cgroup_iter_{start,next,end} 2011-02-07 9:46 ` [PATCH, v5 1/2] cgroups: export cgroup_iter_{start,next,end} Kirill A. Shutsemov @ 2011-02-07 9:57 ` Balbir Singh 0 siblings, 0 replies; 8+ messages in thread From: Balbir Singh @ 2011-02-07 9:57 UTC (permalink / raw) To: Kirill A. Shutsemov Cc: Paul Menage, Li Zefan, containers, jacob.jun.pan, Arjan van de Ven, linux-kernel, Matt Helsley * Kirill A. Shutsemov <kirill@shutemov.name> [2011-02-07 11:46:01]: > From: Kirill A. Shutemov <kirill@shutemov.name> > > Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name> > Acked-by: Paul Menage <menage@google.com> Acked-by: Balbir Singh <balbir@linux.vnet.ibm.com> -- Three Cheers, Balbir ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH, v5 2/2] cgroups: introduce timer slack subsystem 2011-02-07 9:46 [PATCH, v5 0/2] Timer slack cgroup subsystem Kirill A. Shutsemov 2011-02-07 9:46 ` [PATCH, v5 1/2] cgroups: export cgroup_iter_{start,next,end} Kirill A. Shutsemov @ 2011-02-07 9:46 ` Kirill A. Shutsemov 2011-02-07 10:06 ` Balbir Singh 1 sibling, 1 reply; 8+ messages in thread From: Kirill A. Shutsemov @ 2011-02-07 9:46 UTC (permalink / raw) To: Paul Menage, Li Zefan Cc: containers, jacob.jun.pan, Arjan van de Ven, linux-kernel, Matt Helsley, Kirill A. Shutemov From: Kirill A. Shutemov <kirill@shutemov.name> Provides a way of tasks grouping by timer slack value. Introduces per cgroup max and min timer slack value. When a task attaches to a cgroup, its timer slack value adjusts (if needed) to fit min-max range. It also provides a way to set timer slack value for all tasks in the cgroup at once. This functionality is useful in mobile devices where certain background apps are attached to a cgroup and minimum wakeups are desired. Idea-by: Jacob Pan <jacob.jun.pan@linux.intel.com> Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name> --- include/linux/cgroup_subsys.h | 6 + include/linux/init_task.h | 4 +- init/Kconfig | 10 ++ kernel/Makefile | 1 + kernel/cgroup_timer_slack.c | 281 +++++++++++++++++++++++++++++++++++++++++ kernel/sys.c | 19 ++- 6 files changed, 314 insertions(+), 7 deletions(-) create mode 100644 kernel/cgroup_timer_slack.c diff --git a/include/linux/cgroup_subsys.h b/include/linux/cgroup_subsys.h index ccefff0..e399228 100644 --- a/include/linux/cgroup_subsys.h +++ b/include/linux/cgroup_subsys.h @@ -66,3 +66,9 @@ SUBSYS(blkio) #endif /* */ + +#ifdef CONFIG_CGROUP_TIMER_SLACK +SUBSYS(timer_slack) +#endif + +/* */ diff --git a/include/linux/init_task.h b/include/linux/init_task.h index caa151f..48eca8f 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -124,6 +124,8 @@ extern struct cred init_cred; # define INIT_PERF_EVENTS(tsk) #endif +#define TIMER_SLACK_NS_DEFAULT 50000 + /* * INIT_TASK is used to set up the first task table, touch at * your own risk!. Base=0, limit=0x1fffff (=2MB) @@ -177,7 +179,7 @@ extern struct cred init_cred; .cpu_timers = INIT_CPU_TIMERS(tsk.cpu_timers), \ .fs_excl = ATOMIC_INIT(0), \ .pi_lock = __RAW_SPIN_LOCK_UNLOCKED(tsk.pi_lock), \ - .timer_slack_ns = 50000, /* 50 usec default slack */ \ + .timer_slack_ns = TIMER_SLACK_NS_DEFAULT, \ .pids = { \ [PIDTYPE_PID] = INIT_PID_LINK(PIDTYPE_PID), \ [PIDTYPE_PGID] = INIT_PID_LINK(PIDTYPE_PGID), \ diff --git a/init/Kconfig b/init/Kconfig index be788c0..6cf465f 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -596,6 +596,16 @@ config CGROUP_FREEZER Provides a way to freeze and unfreeze all tasks in a cgroup. +config CGROUP_TIMER_SLACK + tristate "Timer slack cgroup subsystem" + help + Provides a way of tasks grouping by timer slack value. + Introduces per cgroup timer slack value which will override + the default timer slack value once a task is attached to a + cgroup. + It's useful in mobile devices where certain background apps + are attached to a cgroup and combined wakeups are desired. + config CGROUP_DEVICE bool "Device controller for cgroups" help diff --git a/kernel/Makefile b/kernel/Makefile index 353d3fe..0b60239 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -61,6 +61,7 @@ obj-$(CONFIG_BACKTRACE_SELF_TEST) += backtracetest.o obj-$(CONFIG_COMPAT) += compat.o obj-$(CONFIG_CGROUPS) += cgroup.o obj-$(CONFIG_CGROUP_FREEZER) += cgroup_freezer.o +obj-$(CONFIG_CGROUP_TIMER_SLACK) += cgroup_timer_slack.o obj-$(CONFIG_CPUSETS) += cpuset.o obj-$(CONFIG_CGROUP_NS) += ns_cgroup.o obj-$(CONFIG_UTS_NS) += utsname.o diff --git a/kernel/cgroup_timer_slack.c b/kernel/cgroup_timer_slack.c new file mode 100644 index 0000000..609e1f1 --- /dev/null +++ b/kernel/cgroup_timer_slack.c @@ -0,0 +1,281 @@ +/* + * cgroup_timer_slack.c - control group timer slack subsystem + * + * Copyright Nokia Corparation, 2011 + * Author: Kirill A. Shutemov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include <linux/cgroup.h> +#include <linux/init_task.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/rcupdate.h> + +struct cgroup_subsys timer_slack_subsys; +struct timer_slack_cgroup { + struct cgroup_subsys_state css; + unsigned long min_slack_ns; + unsigned long max_slack_ns; +}; + +enum { + TIMER_SLACK_MIN, + TIMER_SLACK_MAX, +}; + +extern int (*timer_slack_check)(struct task_struct *task, + unsigned long slack_ns); + +static struct timer_slack_cgroup *cgroup_to_tslack_cgroup(struct cgroup *cgroup) +{ + struct cgroup_subsys_state *css; + + css = cgroup_subsys_state(cgroup, timer_slack_subsys.subsys_id); + return container_of(css, struct timer_slack_cgroup, css); +} + +static int is_timer_slack_allowed(struct timer_slack_cgroup *tslack_cgroup, + unsigned long slack_ns) +{ + if (slack_ns < tslack_cgroup->min_slack_ns || + slack_ns > tslack_cgroup->max_slack_ns) + return false; + return true; +} + +static int cgroup_timer_slack_check(struct task_struct *task, + unsigned long slack_ns) +{ + struct cgroup_subsys_state *css; + struct timer_slack_cgroup *tslack_cgroup; + + /* XXX: lockdep false positive? */ + rcu_read_lock(); + css = task_subsys_state(task, timer_slack_subsys.subsys_id); + tslack_cgroup = container_of(css, struct timer_slack_cgroup, css); + rcu_read_unlock(); + + if (!is_timer_slack_allowed(tslack_cgroup, slack_ns)) + return -EPERM; + return 0; +} + +static struct cgroup_subsys_state * +tslack_cgroup_create(struct cgroup_subsys *subsys, struct cgroup *cgroup) +{ + struct timer_slack_cgroup *tslack_cgroup; + + tslack_cgroup = kmalloc(sizeof(*tslack_cgroup), GFP_KERNEL); + if (!tslack_cgroup) + return ERR_PTR(-ENOMEM); + + if (cgroup->parent) { + struct timer_slack_cgroup *parent; + parent = cgroup_to_tslack_cgroup(cgroup->parent); + tslack_cgroup->min_slack_ns = parent->min_slack_ns; + tslack_cgroup->max_slack_ns = parent->max_slack_ns; + } else { + tslack_cgroup->min_slack_ns = 0UL; + tslack_cgroup->max_slack_ns = ULONG_MAX; + } + + return &tslack_cgroup->css; +} + +static void tslack_cgroup_destroy(struct cgroup_subsys *subsys, + struct cgroup *cgroup) +{ + kfree(cgroup_to_tslack_cgroup(cgroup)); +} + +/* + * Adjust ->timer_slack_ns and ->default_max_slack_ns of the task to fit + * limits of the cgroup. + */ +static void tslack_adjust_task(struct timer_slack_cgroup *tslack_cgroup, + struct task_struct *tsk) +{ + if (tslack_cgroup->min_slack_ns > tsk->timer_slack_ns) + tsk->timer_slack_ns = tslack_cgroup->min_slack_ns; + else if (tslack_cgroup->max_slack_ns < tsk->timer_slack_ns) + tsk->timer_slack_ns = tslack_cgroup->max_slack_ns; + + if (tslack_cgroup->min_slack_ns > tsk->default_timer_slack_ns) + tsk->default_timer_slack_ns = tslack_cgroup->min_slack_ns; + else if (tslack_cgroup->max_slack_ns < tsk->default_timer_slack_ns) + tsk->default_timer_slack_ns = tslack_cgroup->max_slack_ns; +} + +static void tslack_cgroup_attach(struct cgroup_subsys *subsys, + struct cgroup *cgroup, struct cgroup *prev, + struct task_struct *tsk, bool threadgroup) +{ + tslack_adjust_task(cgroup_to_tslack_cgroup(cgroup), tsk); +} + +static int tslack_write_set_slack_ns(struct cgroup *cgroup, struct cftype *cft, + u64 val) +{ + struct timer_slack_cgroup *tslack_cgroup; + struct cgroup_iter it; + struct task_struct *task; + + tslack_cgroup = cgroup_to_tslack_cgroup(cgroup); + if (!is_timer_slack_allowed(cgroup_to_tslack_cgroup(cgroup), val)) + return -EPERM; + + /* Change timer slack value for all tasks in the cgroup */ + cgroup_iter_start(cgroup, &it); + while ((task = cgroup_iter_next(cgroup, &it))) + task->timer_slack_ns = val; + cgroup_iter_end(cgroup, &it); + + return 0; +} + +static u64 tslack_read_range(struct cgroup *cgroup, struct cftype *cft) +{ + struct timer_slack_cgroup *tslack_cgroup; + + tslack_cgroup = cgroup_to_tslack_cgroup(cgroup); + switch (cft->private) { + case TIMER_SLACK_MIN: + return tslack_cgroup->min_slack_ns; + case TIMER_SLACK_MAX: + return tslack_cgroup->max_slack_ns; + default: + BUG(); + }; +} + +static int validate_change(struct cgroup *cgroup, u64 val, int type) +{ + struct timer_slack_cgroup *tslack_cgroup, *child; + struct cgroup *cur; + + BUG_ON(type != TIMER_SLACK_MIN || type != TIMER_SLACK_MAX); + + if (cgroup->parent) { + struct timer_slack_cgroup *parent; + parent = cgroup_to_tslack_cgroup(cgroup->parent); + if (!is_timer_slack_allowed(parent, val)) + return -EPERM; + } + + tslack_cgroup = cgroup_to_tslack_cgroup(cgroup); + if (type == TIMER_SLACK_MIN && val > tslack_cgroup->max_slack_ns) + return -EINVAL; + else if (val < tslack_cgroup->min_slack_ns) + return -EINVAL; + + list_for_each_entry(cur, &cgroup->children, sibling) { + child = cgroup_to_tslack_cgroup(cur); + if (type == TIMER_SLACK_MIN && val > child->min_slack_ns) + return -EBUSY; + else if (val < child->max_slack_ns) + return -EBUSY; + } + + return 0; +} + +static int tslack_write_range(struct cgroup *cgroup, struct cftype *cft, + u64 val) +{ + struct timer_slack_cgroup *tslack_cgroup; + struct cgroup_iter it; + struct task_struct *task; + int err; + + err = validate_change(cgroup, val, cft->private); + if (err) + return err; + + tslack_cgroup = cgroup_to_tslack_cgroup(cgroup); + if (cft->private == TIMER_SLACK_MIN) + tslack_cgroup->min_slack_ns = val; + else + tslack_cgroup->max_slack_ns = val; + + /* + * Adjust timer slack value for all tasks in the cgroup to fit + * min-max range. + */ + cgroup_iter_start(cgroup, &it); + while ((task = cgroup_iter_next(cgroup, &it))) + tslack_adjust_task(tslack_cgroup, task); + cgroup_iter_end(cgroup, &it); + + return 0; +} + +static struct cftype files[] = { + { + .name = "set_slack_ns", + .write_u64 = tslack_write_set_slack_ns, + }, + { + .name = "min_slack_ns", + .private = TIMER_SLACK_MIN, + .read_u64 = tslack_read_range, + .write_u64 = tslack_write_range, + }, + { + .name = "max_slack_ns", + .private = TIMER_SLACK_MAX, + .read_u64 = tslack_read_range, + .write_u64 = tslack_write_range, + }, +}; + +static int tslack_cgroup_populate(struct cgroup_subsys *subsys, + struct cgroup *cgroup) +{ + return cgroup_add_files(cgroup, subsys, files, ARRAY_SIZE(files)); +} + +struct cgroup_subsys timer_slack_subsys = { + .name = "timer_slack", + .module = THIS_MODULE, +#ifdef CONFIG_CGROUP_TIMER_SLACK + .subsys_id = timer_slack_subsys_id, +#endif + .create = tslack_cgroup_create, + .destroy = tslack_cgroup_destroy, + .attach = tslack_cgroup_attach, + .populate = tslack_cgroup_populate, +}; + +static int __init init_cgroup_timer_slack(void) +{ + int err; + + if (timer_slack_check) + return -EBUSY; + timer_slack_check = cgroup_timer_slack_check; + + err = cgroup_load_subsys(&timer_slack_subsys); + if (err) + timer_slack_check = NULL; + return err; +} + +static void __exit exit_cgroup_timer_slack(void) +{ + BUG_ON(timer_slack_check != cgroup_timer_slack_check); + timer_slack_check = NULL; + cgroup_unload_subsys(&timer_slack_subsys); +} + +module_init(init_cgroup_timer_slack); +module_exit(exit_cgroup_timer_slack); +MODULE_LICENSE("GPL"); diff --git a/kernel/sys.c b/kernel/sys.c index 18da702..3bc4205 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -118,6 +118,10 @@ EXPORT_SYMBOL(cad_pid); void (*pm_power_off_prepare)(void); +int (*timer_slack_check)(struct task_struct *task, unsigned long slack_ns) = + NULL; +EXPORT_SYMBOL_GPL(timer_slack_check); + /* * set the priority of a task * - the caller must hold the RCU read lock @@ -1694,12 +1698,15 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, error = current->timer_slack_ns; break; case PR_SET_TIMERSLACK: - if (arg2 <= 0) - current->timer_slack_ns = - current->default_timer_slack_ns; - else - current->timer_slack_ns = arg2; - error = 0; + if (arg2 <= 0) { + me->timer_slack_ns = me->default_timer_slack_ns; + break; + } + + error = timer_slack_check ? + timer_slack_check(me, arg2) : 0; + if (!error) + me->timer_slack_ns = arg2; break; case PR_MCE_KILL: if (arg4 | arg5) -- 1.7.4 ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH, v5 2/2] cgroups: introduce timer slack subsystem 2011-02-07 9:46 ` [PATCH, v5 2/2] cgroups: introduce timer slack subsystem Kirill A. Shutsemov @ 2011-02-07 10:06 ` Balbir Singh 2011-02-07 10:57 ` Kirill A. Shutemov 0 siblings, 1 reply; 8+ messages in thread From: Balbir Singh @ 2011-02-07 10:06 UTC (permalink / raw) To: Kirill A. Shutsemov Cc: Paul Menage, Li Zefan, containers, jacob.jun.pan, Arjan van de Ven, linux-kernel, Matt Helsley * Kirill A. Shutsemov <kirill@shutemov.name> [2011-02-07 11:46:02]: > From: Kirill A. Shutemov <kirill@shutemov.name> > > Provides a way of tasks grouping by timer slack value. Introduces per > cgroup max and min timer slack value. When a task attaches to a cgroup, > its timer slack value adjusts (if needed) to fit min-max range. > > It also provides a way to set timer slack value for all tasks in the > cgroup at once. > > This functionality is useful in mobile devices where certain background > apps are attached to a cgroup and minimum wakeups are desired. > > Idea-by: Jacob Pan <jacob.jun.pan@linux.intel.com> > Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name> > --- > include/linux/cgroup_subsys.h | 6 + > include/linux/init_task.h | 4 +- > init/Kconfig | 10 ++ > kernel/Makefile | 1 + > kernel/cgroup_timer_slack.c | 281 +++++++++++++++++++++++++++++++++++++++++ > kernel/sys.c | 19 ++- > 6 files changed, 314 insertions(+), 7 deletions(-) > create mode 100644 kernel/cgroup_timer_slack.c > > diff --git a/include/linux/cgroup_subsys.h b/include/linux/cgroup_subsys.h > index ccefff0..e399228 100644 > --- a/include/linux/cgroup_subsys.h > +++ b/include/linux/cgroup_subsys.h > @@ -66,3 +66,9 @@ SUBSYS(blkio) > #endif > > /* */ > + > +#ifdef CONFIG_CGROUP_TIMER_SLACK > +SUBSYS(timer_slack) > +#endif > + > +/* */ > diff --git a/include/linux/init_task.h b/include/linux/init_task.h > index caa151f..48eca8f 100644 > --- a/include/linux/init_task.h > +++ b/include/linux/init_task.h > @@ -124,6 +124,8 @@ extern struct cred init_cred; > # define INIT_PERF_EVENTS(tsk) > #endif > > +#define TIMER_SLACK_NS_DEFAULT 50000 > + > /* > * INIT_TASK is used to set up the first task table, touch at > * your own risk!. Base=0, limit=0x1fffff (=2MB) > @@ -177,7 +179,7 @@ extern struct cred init_cred; > .cpu_timers = INIT_CPU_TIMERS(tsk.cpu_timers), \ > .fs_excl = ATOMIC_INIT(0), \ > .pi_lock = __RAW_SPIN_LOCK_UNLOCKED(tsk.pi_lock), \ > - .timer_slack_ns = 50000, /* 50 usec default slack */ \ > + .timer_slack_ns = TIMER_SLACK_NS_DEFAULT, \ > .pids = { \ > [PIDTYPE_PID] = INIT_PID_LINK(PIDTYPE_PID), \ > [PIDTYPE_PGID] = INIT_PID_LINK(PIDTYPE_PGID), \ > diff --git a/init/Kconfig b/init/Kconfig > index be788c0..6cf465f 100644 > --- a/init/Kconfig > +++ b/init/Kconfig > @@ -596,6 +596,16 @@ config CGROUP_FREEZER > Provides a way to freeze and unfreeze all tasks in a > cgroup. > > +config CGROUP_TIMER_SLACK > + tristate "Timer slack cgroup subsystem" > + help > + Provides a way of tasks grouping by timer slack value. > + Introduces per cgroup timer slack value which will override > + the default timer slack value once a task is attached to a > + cgroup. > + It's useful in mobile devices where certain background apps > + are attached to a cgroup and combined wakeups are desired. > + > config CGROUP_DEVICE > bool "Device controller for cgroups" > help > diff --git a/kernel/Makefile b/kernel/Makefile > index 353d3fe..0b60239 100644 > --- a/kernel/Makefile > +++ b/kernel/Makefile > @@ -61,6 +61,7 @@ obj-$(CONFIG_BACKTRACE_SELF_TEST) += backtracetest.o > obj-$(CONFIG_COMPAT) += compat.o > obj-$(CONFIG_CGROUPS) += cgroup.o > obj-$(CONFIG_CGROUP_FREEZER) += cgroup_freezer.o > +obj-$(CONFIG_CGROUP_TIMER_SLACK) += cgroup_timer_slack.o > obj-$(CONFIG_CPUSETS) += cpuset.o > obj-$(CONFIG_CGROUP_NS) += ns_cgroup.o > obj-$(CONFIG_UTS_NS) += utsname.o > diff --git a/kernel/cgroup_timer_slack.c b/kernel/cgroup_timer_slack.c > new file mode 100644 > index 0000000..609e1f1 > --- /dev/null > +++ b/kernel/cgroup_timer_slack.c > @@ -0,0 +1,281 @@ > +/* > + * cgroup_timer_slack.c - control group timer slack subsystem > + * > + * Copyright Nokia Corparation, 2011 > + * Author: Kirill A. Shutemov > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + */ > +#include <linux/cgroup.h> > +#include <linux/init_task.h> > +#include <linux/module.h> > +#include <linux/slab.h> > +#include <linux/rcupdate.h> > + > +struct cgroup_subsys timer_slack_subsys; > +struct timer_slack_cgroup { > + struct cgroup_subsys_state css; > + unsigned long min_slack_ns; > + unsigned long max_slack_ns; > +}; > + > +enum { > + TIMER_SLACK_MIN, > + TIMER_SLACK_MAX, > +}; > + > +extern int (*timer_slack_check)(struct task_struct *task, > + unsigned long slack_ns); > + > +static struct timer_slack_cgroup *cgroup_to_tslack_cgroup(struct cgroup *cgroup) > +{ > + struct cgroup_subsys_state *css; > + > + css = cgroup_subsys_state(cgroup, timer_slack_subsys.subsys_id); > + return container_of(css, struct timer_slack_cgroup, css); > +} > + > +static int is_timer_slack_allowed(struct timer_slack_cgroup *tslack_cgroup, > + unsigned long slack_ns) > +{ > + if (slack_ns < tslack_cgroup->min_slack_ns || > + slack_ns > tslack_cgroup->max_slack_ns) > + return false; > + return true; > +} > + > +static int cgroup_timer_slack_check(struct task_struct *task, > + unsigned long slack_ns) > +{ > + struct cgroup_subsys_state *css; > + struct timer_slack_cgroup *tslack_cgroup; > + > + /* XXX: lockdep false positive? */ > + rcu_read_lock(); > + css = task_subsys_state(task, timer_slack_subsys.subsys_id); > + tslack_cgroup = container_of(css, struct timer_slack_cgroup, css); Shouldn't the rcu_read_unlock() be after the check of is_timer_slack_allowed()? > + rcu_read_unlock(); > + > + if (!is_timer_slack_allowed(tslack_cgroup, slack_ns)) > + return -EPERM; > + return 0; > +} > + > +static struct cgroup_subsys_state * > +tslack_cgroup_create(struct cgroup_subsys *subsys, struct cgroup *cgroup) > +{ > + struct timer_slack_cgroup *tslack_cgroup; > + > + tslack_cgroup = kmalloc(sizeof(*tslack_cgroup), GFP_KERNEL); > + if (!tslack_cgroup) > + return ERR_PTR(-ENOMEM); > + > + if (cgroup->parent) { > + struct timer_slack_cgroup *parent; > + parent = cgroup_to_tslack_cgroup(cgroup->parent); > + tslack_cgroup->min_slack_ns = parent->min_slack_ns; > + tslack_cgroup->max_slack_ns = parent->max_slack_ns; > + } else { > + tslack_cgroup->min_slack_ns = 0UL; > + tslack_cgroup->max_slack_ns = ULONG_MAX; > + } > + > + return &tslack_cgroup->css; > +} > + > +static void tslack_cgroup_destroy(struct cgroup_subsys *subsys, > + struct cgroup *cgroup) > +{ > + kfree(cgroup_to_tslack_cgroup(cgroup)); > +} > + > +/* > + * Adjust ->timer_slack_ns and ->default_max_slack_ns of the task to fit > + * limits of the cgroup. > + */ > +static void tslack_adjust_task(struct timer_slack_cgroup *tslack_cgroup, > + struct task_struct *tsk) > +{ > + if (tslack_cgroup->min_slack_ns > tsk->timer_slack_ns) > + tsk->timer_slack_ns = tslack_cgroup->min_slack_ns; > + else if (tslack_cgroup->max_slack_ns < tsk->timer_slack_ns) > + tsk->timer_slack_ns = tslack_cgroup->max_slack_ns; > + > + if (tslack_cgroup->min_slack_ns > tsk->default_timer_slack_ns) > + tsk->default_timer_slack_ns = tslack_cgroup->min_slack_ns; > + else if (tslack_cgroup->max_slack_ns < tsk->default_timer_slack_ns) > + tsk->default_timer_slack_ns = tslack_cgroup->max_slack_ns; > +} > + > +static void tslack_cgroup_attach(struct cgroup_subsys *subsys, > + struct cgroup *cgroup, struct cgroup *prev, > + struct task_struct *tsk, bool threadgroup) > +{ > + tslack_adjust_task(cgroup_to_tslack_cgroup(cgroup), tsk); > +} > + > +static int tslack_write_set_slack_ns(struct cgroup *cgroup, struct cftype *cft, > + u64 val) > +{ > + struct timer_slack_cgroup *tslack_cgroup; > + struct cgroup_iter it; > + struct task_struct *task; > + > + tslack_cgroup = cgroup_to_tslack_cgroup(cgroup); > + if (!is_timer_slack_allowed(cgroup_to_tslack_cgroup(cgroup), val)) > + return -EPERM; > + > + /* Change timer slack value for all tasks in the cgroup */ > + cgroup_iter_start(cgroup, &it); > + while ((task = cgroup_iter_next(cgroup, &it))) > + task->timer_slack_ns = val; > + cgroup_iter_end(cgroup, &it); OK, I've got questions, are the following possible 1. Assign a task to a cgroup based on timer slack, it is accepted based on min and max values 2. We update the slack Can't this be bad for some tasks, is there a way for a task to prevent the max slack from being updated? 2. Can there be an overlap in the ranges? -- Three Cheers, Balbir ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH, v5 2/2] cgroups: introduce timer slack subsystem 2011-02-07 10:06 ` Balbir Singh @ 2011-02-07 10:57 ` Kirill A. Shutemov 2011-02-07 12:14 ` Balbir Singh 0 siblings, 1 reply; 8+ messages in thread From: Kirill A. Shutemov @ 2011-02-07 10:57 UTC (permalink / raw) To: Balbir Singh Cc: Paul Menage, Li Zefan, containers, jacob.jun.pan, Arjan van de Ven, linux-kernel, Matt Helsley On Mon, Feb 07, 2011 at 03:36:24PM +0530, Balbir Singh wrote: > * Kirill A. Shutsemov <kirill@shutemov.name> [2011-02-07 11:46:02]: > > > From: Kirill A. Shutemov <kirill@shutemov.name> > > > > Provides a way of tasks grouping by timer slack value. Introduces per > > cgroup max and min timer slack value. When a task attaches to a cgroup, > > its timer slack value adjusts (if needed) to fit min-max range. > > > > It also provides a way to set timer slack value for all tasks in the > > cgroup at once. > > > > This functionality is useful in mobile devices where certain background > > apps are attached to a cgroup and minimum wakeups are desired. > > > > Idea-by: Jacob Pan <jacob.jun.pan@linux.intel.com> > > Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name> > > --- > > include/linux/cgroup_subsys.h | 6 + > > include/linux/init_task.h | 4 +- > > init/Kconfig | 10 ++ > > kernel/Makefile | 1 + > > kernel/cgroup_timer_slack.c | 281 +++++++++++++++++++++++++++++++++++++++++ > > kernel/sys.c | 19 ++- > > 6 files changed, 314 insertions(+), 7 deletions(-) > > create mode 100644 kernel/cgroup_timer_slack.c > > > > diff --git a/include/linux/cgroup_subsys.h b/include/linux/cgroup_subsys.h > > index ccefff0..e399228 100644 > > --- a/include/linux/cgroup_subsys.h > > +++ b/include/linux/cgroup_subsys.h > > @@ -66,3 +66,9 @@ SUBSYS(blkio) > > #endif > > > > /* */ > > + > > +#ifdef CONFIG_CGROUP_TIMER_SLACK > > +SUBSYS(timer_slack) > > +#endif > > + > > +/* */ > > diff --git a/include/linux/init_task.h b/include/linux/init_task.h > > index caa151f..48eca8f 100644 > > --- a/include/linux/init_task.h > > +++ b/include/linux/init_task.h > > @@ -124,6 +124,8 @@ extern struct cred init_cred; > > # define INIT_PERF_EVENTS(tsk) > > #endif > > > > +#define TIMER_SLACK_NS_DEFAULT 50000 > > + > > /* > > * INIT_TASK is used to set up the first task table, touch at > > * your own risk!. Base=0, limit=0x1fffff (=2MB) > > @@ -177,7 +179,7 @@ extern struct cred init_cred; > > .cpu_timers = INIT_CPU_TIMERS(tsk.cpu_timers), \ > > .fs_excl = ATOMIC_INIT(0), \ > > .pi_lock = __RAW_SPIN_LOCK_UNLOCKED(tsk.pi_lock), \ > > - .timer_slack_ns = 50000, /* 50 usec default slack */ \ > > + .timer_slack_ns = TIMER_SLACK_NS_DEFAULT, \ > > .pids = { \ > > [PIDTYPE_PID] = INIT_PID_LINK(PIDTYPE_PID), \ > > [PIDTYPE_PGID] = INIT_PID_LINK(PIDTYPE_PGID), \ > > diff --git a/init/Kconfig b/init/Kconfig > > index be788c0..6cf465f 100644 > > --- a/init/Kconfig > > +++ b/init/Kconfig > > @@ -596,6 +596,16 @@ config CGROUP_FREEZER > > Provides a way to freeze and unfreeze all tasks in a > > cgroup. > > > > +config CGROUP_TIMER_SLACK > > + tristate "Timer slack cgroup subsystem" > > + help > > + Provides a way of tasks grouping by timer slack value. > > + Introduces per cgroup timer slack value which will override > > + the default timer slack value once a task is attached to a > > + cgroup. > > + It's useful in mobile devices where certain background apps > > + are attached to a cgroup and combined wakeups are desired. > > + > > config CGROUP_DEVICE > > bool "Device controller for cgroups" > > help > > diff --git a/kernel/Makefile b/kernel/Makefile > > index 353d3fe..0b60239 100644 > > --- a/kernel/Makefile > > +++ b/kernel/Makefile > > @@ -61,6 +61,7 @@ obj-$(CONFIG_BACKTRACE_SELF_TEST) += backtracetest.o > > obj-$(CONFIG_COMPAT) += compat.o > > obj-$(CONFIG_CGROUPS) += cgroup.o > > obj-$(CONFIG_CGROUP_FREEZER) += cgroup_freezer.o > > +obj-$(CONFIG_CGROUP_TIMER_SLACK) += cgroup_timer_slack.o > > obj-$(CONFIG_CPUSETS) += cpuset.o > > obj-$(CONFIG_CGROUP_NS) += ns_cgroup.o > > obj-$(CONFIG_UTS_NS) += utsname.o > > diff --git a/kernel/cgroup_timer_slack.c b/kernel/cgroup_timer_slack.c > > new file mode 100644 > > index 0000000..609e1f1 > > --- /dev/null > > +++ b/kernel/cgroup_timer_slack.c > > @@ -0,0 +1,281 @@ > > +/* > > + * cgroup_timer_slack.c - control group timer slack subsystem > > + * > > + * Copyright Nokia Corparation, 2011 > > + * Author: Kirill A. Shutemov > > + * > > + * This program is free software; you can redistribute it and/or modify > > + * it under the terms of the GNU General Public License as published by > > + * the Free Software Foundation; either version 2 of the License, or > > + * (at your option) any later version. > > + * > > + * This program is distributed in the hope that it will be useful, > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > + * GNU General Public License for more details. > > + */ > > +#include <linux/cgroup.h> > > +#include <linux/init_task.h> > > +#include <linux/module.h> > > +#include <linux/slab.h> > > +#include <linux/rcupdate.h> > > + > > +struct cgroup_subsys timer_slack_subsys; > > +struct timer_slack_cgroup { > > + struct cgroup_subsys_state css; > > + unsigned long min_slack_ns; > > + unsigned long max_slack_ns; > > +}; > > + > > +enum { > > + TIMER_SLACK_MIN, > > + TIMER_SLACK_MAX, > > +}; > > + > > +extern int (*timer_slack_check)(struct task_struct *task, > > + unsigned long slack_ns); > > + > > +static struct timer_slack_cgroup *cgroup_to_tslack_cgroup(struct cgroup *cgroup) > > +{ > > + struct cgroup_subsys_state *css; > > + > > + css = cgroup_subsys_state(cgroup, timer_slack_subsys.subsys_id); > > + return container_of(css, struct timer_slack_cgroup, css); > > +} > > + > > +static int is_timer_slack_allowed(struct timer_slack_cgroup *tslack_cgroup, > > + unsigned long slack_ns) > > +{ > > + if (slack_ns < tslack_cgroup->min_slack_ns || > > + slack_ns > tslack_cgroup->max_slack_ns) > > + return false; > > + return true; > > +} > > + > > +static int cgroup_timer_slack_check(struct task_struct *task, > > + unsigned long slack_ns) > > +{ > > + struct cgroup_subsys_state *css; > > + struct timer_slack_cgroup *tslack_cgroup; > > + > > + /* XXX: lockdep false positive? */ > > + rcu_read_lock(); > > + css = task_subsys_state(task, timer_slack_subsys.subsys_id); > > + tslack_cgroup = container_of(css, struct timer_slack_cgroup, css); > > Shouldn't the rcu_read_unlock() be after the check of is_timer_slack_allowed()? I'm not sure if this rcu_read_lock() is needed. See freezer_fork(). > > + rcu_read_unlock(); > > + > > + if (!is_timer_slack_allowed(tslack_cgroup, slack_ns)) > > + return -EPERM; > > + return 0; > > +} > > + > > +static struct cgroup_subsys_state * > > +tslack_cgroup_create(struct cgroup_subsys *subsys, struct cgroup *cgroup) > > +{ > > + struct timer_slack_cgroup *tslack_cgroup; > > + > > + tslack_cgroup = kmalloc(sizeof(*tslack_cgroup), GFP_KERNEL); > > + if (!tslack_cgroup) > > + return ERR_PTR(-ENOMEM); > > + > > + if (cgroup->parent) { > > + struct timer_slack_cgroup *parent; > > + parent = cgroup_to_tslack_cgroup(cgroup->parent); > > + tslack_cgroup->min_slack_ns = parent->min_slack_ns; > > + tslack_cgroup->max_slack_ns = parent->max_slack_ns; > > + } else { > > + tslack_cgroup->min_slack_ns = 0UL; > > + tslack_cgroup->max_slack_ns = ULONG_MAX; > > + } > > + > > + return &tslack_cgroup->css; > > +} > > + > > +static void tslack_cgroup_destroy(struct cgroup_subsys *subsys, > > + struct cgroup *cgroup) > > +{ > > + kfree(cgroup_to_tslack_cgroup(cgroup)); > > +} > > + > > +/* > > + * Adjust ->timer_slack_ns and ->default_max_slack_ns of the task to fit > > + * limits of the cgroup. > > + */ > > +static void tslack_adjust_task(struct timer_slack_cgroup *tslack_cgroup, > > + struct task_struct *tsk) > > +{ > > + if (tslack_cgroup->min_slack_ns > tsk->timer_slack_ns) > > + tsk->timer_slack_ns = tslack_cgroup->min_slack_ns; > > + else if (tslack_cgroup->max_slack_ns < tsk->timer_slack_ns) > > + tsk->timer_slack_ns = tslack_cgroup->max_slack_ns; > > + > > + if (tslack_cgroup->min_slack_ns > tsk->default_timer_slack_ns) > > + tsk->default_timer_slack_ns = tslack_cgroup->min_slack_ns; > > + else if (tslack_cgroup->max_slack_ns < tsk->default_timer_slack_ns) > > + tsk->default_timer_slack_ns = tslack_cgroup->max_slack_ns; > > +} > > + > > +static void tslack_cgroup_attach(struct cgroup_subsys *subsys, > > + struct cgroup *cgroup, struct cgroup *prev, > > + struct task_struct *tsk, bool threadgroup) > > +{ > > + tslack_adjust_task(cgroup_to_tslack_cgroup(cgroup), tsk); > > +} > > + > > +static int tslack_write_set_slack_ns(struct cgroup *cgroup, struct cftype *cft, > > + u64 val) > > +{ > > + struct timer_slack_cgroup *tslack_cgroup; > > + struct cgroup_iter it; > > + struct task_struct *task; > > + > > + tslack_cgroup = cgroup_to_tslack_cgroup(cgroup); > > + if (!is_timer_slack_allowed(cgroup_to_tslack_cgroup(cgroup), val)) > > + return -EPERM; > > + > > + /* Change timer slack value for all tasks in the cgroup */ > > + cgroup_iter_start(cgroup, &it); > > + while ((task = cgroup_iter_next(cgroup, &it))) > > + task->timer_slack_ns = val; > > + cgroup_iter_end(cgroup, &it); > > OK, I've got questions, are the following possible > > 1. Assign a task to a cgroup based on timer slack, it is accepted > based on min and max values Hm.. Currently, there is no such functionality. Do we need it? What's use case? > 2. We update the slack > > Can't this be bad for some tasks, is there a way for a task to prevent > the max slack from being updated? If a non-RT task can't tolerate not being on time it's totally broken. RT-tasks are not affected by timer slack. And we believe that user knows what he does. > 2. Can there be an overlap in the ranges? What overlap do you mean? There is only one rule: parent's range should be wider then child's. -- Kirill A. Shutemov ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH, v5 2/2] cgroups: introduce timer slack subsystem 2011-02-07 10:57 ` Kirill A. Shutemov @ 2011-02-07 12:14 ` Balbir Singh 2011-02-07 12:26 ` Kirill A. Shutemov 0 siblings, 1 reply; 8+ messages in thread From: Balbir Singh @ 2011-02-07 12:14 UTC (permalink / raw) To: Kirill A. Shutemov Cc: Paul Menage, Li Zefan, containers, jacob.jun.pan, Arjan van de Ven, linux-kernel, Matt Helsley * Kirill A. Shutemov <kirill@shutemov.name> [2011-02-07 12:57:30]: > On Mon, Feb 07, 2011 at 03:36:24PM +0530, Balbir Singh wrote: > > * Kirill A. Shutsemov <kirill@shutemov.name> [2011-02-07 11:46:02]: > > > > > From: Kirill A. Shutemov <kirill@shutemov.name> > > > > > > Provides a way of tasks grouping by timer slack value. Introduces per > > > cgroup max and min timer slack value. When a task attaches to a cgroup, > > > its timer slack value adjusts (if needed) to fit min-max range. > > > > > > It also provides a way to set timer slack value for all tasks in the > > > cgroup at once. > > > > > > This functionality is useful in mobile devices where certain background > > > apps are attached to a cgroup and minimum wakeups are desired. > > > > > > Idea-by: Jacob Pan <jacob.jun.pan@linux.intel.com> > > > Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name> > > > --- > > > include/linux/cgroup_subsys.h | 6 + > > > include/linux/init_task.h | 4 +- > > > init/Kconfig | 10 ++ > > > kernel/Makefile | 1 + > > > kernel/cgroup_timer_slack.c | 281 +++++++++++++++++++++++++++++++++++++++++ > > > kernel/sys.c | 19 ++- > > > 6 files changed, 314 insertions(+), 7 deletions(-) > > > create mode 100644 kernel/cgroup_timer_slack.c > > > > > > diff --git a/include/linux/cgroup_subsys.h b/include/linux/cgroup_subsys.h > > > index ccefff0..e399228 100644 > > > --- a/include/linux/cgroup_subsys.h > > > +++ b/include/linux/cgroup_subsys.h > > > @@ -66,3 +66,9 @@ SUBSYS(blkio) > > > #endif > > > > > > /* */ > > > + > > > +#ifdef CONFIG_CGROUP_TIMER_SLACK > > > +SUBSYS(timer_slack) > > > +#endif > > > + > > > +/* */ > > > diff --git a/include/linux/init_task.h b/include/linux/init_task.h > > > index caa151f..48eca8f 100644 > > > --- a/include/linux/init_task.h > > > +++ b/include/linux/init_task.h > > > @@ -124,6 +124,8 @@ extern struct cred init_cred; > > > # define INIT_PERF_EVENTS(tsk) > > > #endif > > > > > > +#define TIMER_SLACK_NS_DEFAULT 50000 > > > + > > > /* > > > * INIT_TASK is used to set up the first task table, touch at > > > * your own risk!. Base=0, limit=0x1fffff (=2MB) > > > @@ -177,7 +179,7 @@ extern struct cred init_cred; > > > .cpu_timers = INIT_CPU_TIMERS(tsk.cpu_timers), \ > > > .fs_excl = ATOMIC_INIT(0), \ > > > .pi_lock = __RAW_SPIN_LOCK_UNLOCKED(tsk.pi_lock), \ > > > - .timer_slack_ns = 50000, /* 50 usec default slack */ \ > > > + .timer_slack_ns = TIMER_SLACK_NS_DEFAULT, \ > > > .pids = { \ > > > [PIDTYPE_PID] = INIT_PID_LINK(PIDTYPE_PID), \ > > > [PIDTYPE_PGID] = INIT_PID_LINK(PIDTYPE_PGID), \ > > > diff --git a/init/Kconfig b/init/Kconfig > > > index be788c0..6cf465f 100644 > > > --- a/init/Kconfig > > > +++ b/init/Kconfig > > > @@ -596,6 +596,16 @@ config CGROUP_FREEZER > > > Provides a way to freeze and unfreeze all tasks in a > > > cgroup. > > > > > > +config CGROUP_TIMER_SLACK > > > + tristate "Timer slack cgroup subsystem" > > > + help > > > + Provides a way of tasks grouping by timer slack value. > > > + Introduces per cgroup timer slack value which will override > > > + the default timer slack value once a task is attached to a > > > + cgroup. > > > + It's useful in mobile devices where certain background apps > > > + are attached to a cgroup and combined wakeups are desired. > > > + > > > config CGROUP_DEVICE > > > bool "Device controller for cgroups" > > > help > > > diff --git a/kernel/Makefile b/kernel/Makefile > > > index 353d3fe..0b60239 100644 > > > --- a/kernel/Makefile > > > +++ b/kernel/Makefile > > > @@ -61,6 +61,7 @@ obj-$(CONFIG_BACKTRACE_SELF_TEST) += backtracetest.o > > > obj-$(CONFIG_COMPAT) += compat.o > > > obj-$(CONFIG_CGROUPS) += cgroup.o > > > obj-$(CONFIG_CGROUP_FREEZER) += cgroup_freezer.o > > > +obj-$(CONFIG_CGROUP_TIMER_SLACK) += cgroup_timer_slack.o > > > obj-$(CONFIG_CPUSETS) += cpuset.o > > > obj-$(CONFIG_CGROUP_NS) += ns_cgroup.o > > > obj-$(CONFIG_UTS_NS) += utsname.o > > > diff --git a/kernel/cgroup_timer_slack.c b/kernel/cgroup_timer_slack.c > > > new file mode 100644 > > > index 0000000..609e1f1 > > > --- /dev/null > > > +++ b/kernel/cgroup_timer_slack.c > > > @@ -0,0 +1,281 @@ > > > +/* > > > + * cgroup_timer_slack.c - control group timer slack subsystem > > > + * > > > + * Copyright Nokia Corparation, 2011 > > > + * Author: Kirill A. Shutemov > > > + * > > > + * This program is free software; you can redistribute it and/or modify > > > + * it under the terms of the GNU General Public License as published by > > > + * the Free Software Foundation; either version 2 of the License, or > > > + * (at your option) any later version. > > > + * > > > + * This program is distributed in the hope that it will be useful, > > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > > + * GNU General Public License for more details. > > > + */ > > > +#include <linux/cgroup.h> > > > +#include <linux/init_task.h> > > > +#include <linux/module.h> > > > +#include <linux/slab.h> > > > +#include <linux/rcupdate.h> > > > + > > > +struct cgroup_subsys timer_slack_subsys; > > > +struct timer_slack_cgroup { > > > + struct cgroup_subsys_state css; > > > + unsigned long min_slack_ns; > > > + unsigned long max_slack_ns; > > > +}; > > > + > > > +enum { > > > + TIMER_SLACK_MIN, > > > + TIMER_SLACK_MAX, > > > +}; > > > + > > > +extern int (*timer_slack_check)(struct task_struct *task, > > > + unsigned long slack_ns); > > > + > > > +static struct timer_slack_cgroup *cgroup_to_tslack_cgroup(struct cgroup *cgroup) > > > +{ > > > + struct cgroup_subsys_state *css; > > > + > > > + css = cgroup_subsys_state(cgroup, timer_slack_subsys.subsys_id); > > > + return container_of(css, struct timer_slack_cgroup, css); > > > +} > > > + > > > +static int is_timer_slack_allowed(struct timer_slack_cgroup *tslack_cgroup, > > > + unsigned long slack_ns) > > > +{ > > > + if (slack_ns < tslack_cgroup->min_slack_ns || > > > + slack_ns > tslack_cgroup->max_slack_ns) > > > + return false; > > > + return true; > > > +} > > > + > > > +static int cgroup_timer_slack_check(struct task_struct *task, > > > + unsigned long slack_ns) > > > +{ > > > + struct cgroup_subsys_state *css; > > > + struct timer_slack_cgroup *tslack_cgroup; > > > + > > > + /* XXX: lockdep false positive? */ > > > + rcu_read_lock(); > > > + css = task_subsys_state(task, timer_slack_subsys.subsys_id); > > > + tslack_cgroup = container_of(css, struct timer_slack_cgroup, css); > > > > Shouldn't the rcu_read_unlock() be after the check of is_timer_slack_allowed()? > > I'm not sure if this rcu_read_lock() is needed. See freezer_fork(). > > > > + rcu_read_unlock(); > > > + > > > + if (!is_timer_slack_allowed(tslack_cgroup, slack_ns)) > > > + return -EPERM; > > > + return 0; > > > +} > > > + > > > +static struct cgroup_subsys_state * > > > +tslack_cgroup_create(struct cgroup_subsys *subsys, struct cgroup *cgroup) > > > +{ > > > + struct timer_slack_cgroup *tslack_cgroup; > > > + > > > + tslack_cgroup = kmalloc(sizeof(*tslack_cgroup), GFP_KERNEL); > > > + if (!tslack_cgroup) > > > + return ERR_PTR(-ENOMEM); > > > + > > > + if (cgroup->parent) { > > > + struct timer_slack_cgroup *parent; > > > + parent = cgroup_to_tslack_cgroup(cgroup->parent); > > > + tslack_cgroup->min_slack_ns = parent->min_slack_ns; > > > + tslack_cgroup->max_slack_ns = parent->max_slack_ns; > > > + } else { > > > + tslack_cgroup->min_slack_ns = 0UL; > > > + tslack_cgroup->max_slack_ns = ULONG_MAX; > > > + } > > > + > > > + return &tslack_cgroup->css; > > > +} > > > + > > > +static void tslack_cgroup_destroy(struct cgroup_subsys *subsys, > > > + struct cgroup *cgroup) > > > +{ > > > + kfree(cgroup_to_tslack_cgroup(cgroup)); > > > +} > > > + > > > +/* > > > + * Adjust ->timer_slack_ns and ->default_max_slack_ns of the task to fit > > > + * limits of the cgroup. > > > + */ > > > +static void tslack_adjust_task(struct timer_slack_cgroup *tslack_cgroup, > > > + struct task_struct *tsk) > > > +{ > > > + if (tslack_cgroup->min_slack_ns > tsk->timer_slack_ns) > > > + tsk->timer_slack_ns = tslack_cgroup->min_slack_ns; > > > + else if (tslack_cgroup->max_slack_ns < tsk->timer_slack_ns) > > > + tsk->timer_slack_ns = tslack_cgroup->max_slack_ns; > > > + > > > + if (tslack_cgroup->min_slack_ns > tsk->default_timer_slack_ns) > > > + tsk->default_timer_slack_ns = tslack_cgroup->min_slack_ns; > > > + else if (tslack_cgroup->max_slack_ns < tsk->default_timer_slack_ns) > > > + tsk->default_timer_slack_ns = tslack_cgroup->max_slack_ns; > > > +} > > > + > > > +static void tslack_cgroup_attach(struct cgroup_subsys *subsys, > > > + struct cgroup *cgroup, struct cgroup *prev, > > > + struct task_struct *tsk, bool threadgroup) > > > +{ > > > + tslack_adjust_task(cgroup_to_tslack_cgroup(cgroup), tsk); > > > +} > > > + > > > +static int tslack_write_set_slack_ns(struct cgroup *cgroup, struct cftype *cft, > > > + u64 val) > > > +{ > > > + struct timer_slack_cgroup *tslack_cgroup; > > > + struct cgroup_iter it; > > > + struct task_struct *task; > > > + > > > + tslack_cgroup = cgroup_to_tslack_cgroup(cgroup); > > > + if (!is_timer_slack_allowed(cgroup_to_tslack_cgroup(cgroup), val)) > > > + return -EPERM; > > > + > > > + /* Change timer slack value for all tasks in the cgroup */ > > > + cgroup_iter_start(cgroup, &it); > > > + while ((task = cgroup_iter_next(cgroup, &it))) > > > + task->timer_slack_ns = val; > > > + cgroup_iter_end(cgroup, &it); > > > > OK, I've got questions, are the following possible > > > > 1. Assign a task to a cgroup based on timer slack, it is accepted > > based on min and max values > > Hm.. Currently, there is no such functionality. Do we need it? What's use > case? > > > 2. We update the slack > > > > Can't this be bad for some tasks, is there a way for a task to prevent > > the max slack from being updated? > > If a non-RT task can't tolerate not being on time it's totally broken. Yes, I agree, except that the slack might be overwritten after the application set an acceptable slack. > RT-tasks are not affected by timer slack. > > And we believe that user knows what he does. > > > 2. Can there be an overlap in the ranges? > > What overlap do you mean? > There is only one rule: parent's range should be wider then child's. Between the children, can we have something like 10-200 / \ / \ V V 10-110 100-200 -- Three Cheers, Balbir ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH, v5 2/2] cgroups: introduce timer slack subsystem 2011-02-07 12:14 ` Balbir Singh @ 2011-02-07 12:26 ` Kirill A. Shutemov 0 siblings, 0 replies; 8+ messages in thread From: Kirill A. Shutemov @ 2011-02-07 12:26 UTC (permalink / raw) To: Balbir Singh Cc: Paul Menage, Li Zefan, containers, jacob.jun.pan, Arjan van de Ven, linux-kernel, Matt Helsley On Mon, Feb 07, 2011 at 05:44:30PM +0530, Balbir Singh wrote: > * Kirill A. Shutemov <kirill@shutemov.name> [2011-02-07 12:57:30]: > > > On Mon, Feb 07, 2011 at 03:36:24PM +0530, Balbir Singh wrote: > > > 2. Can there be an overlap in the ranges? > > > > What overlap do you mean? > > There is only one rule: parent's range should be wider then child's. > > Between the children, can we have something like > > 10-200 > / \ > / \ > V V > 10-110 100-200 Yes, sure. -- Kirill A. Shutemov ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2011-02-07 12:26 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-02-07 9:46 [PATCH, v5 0/2] Timer slack cgroup subsystem Kirill A. Shutsemov
2011-02-07 9:46 ` [PATCH, v5 1/2] cgroups: export cgroup_iter_{start,next,end} Kirill A. Shutsemov
2011-02-07 9:57 ` Balbir Singh
2011-02-07 9:46 ` [PATCH, v5 2/2] cgroups: introduce timer slack subsystem Kirill A. Shutsemov
2011-02-07 10:06 ` Balbir Singh
2011-02-07 10:57 ` Kirill A. Shutemov
2011-02-07 12:14 ` Balbir Singh
2011-02-07 12:26 ` Kirill A. Shutemov
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®