diff --git a/packages/linux/patches/linux-2.6.37-rc2-120_RFC-RFT-v3-sched-automated-per-tty-task-groups.patch b/packages/linux/patches/linux-2.6.37-rc2-120_RFC-RFT-v3-sched-automated-per-tty-task-groups.patch new file mode 100644 index 0000000000..25f948c4b8 --- /dev/null +++ b/packages/linux/patches/linux-2.6.37-rc2-120_RFC-RFT-v3-sched-automated-per-tty-task-groups.patch @@ -0,0 +1,359 @@ +Index: linux-2.6/include/linux/sched.h +=================================================================== +--- linux-2.6.orig/include/linux/sched.h ++++ linux-2.6/include/linux/sched.h +@@ -509,6 +509,8 @@ struct thread_group_cputimer { + spinlock_t lock; + }; + ++struct autogroup; ++ + /* + * NOTE! "signal_struct" does not have it's own + * locking, because a shared signal_struct always +@@ -576,6 +578,9 @@ struct signal_struct { + + struct tty_struct *tty; /* NULL if no tty */ + ++#ifdef CONFIG_SCHED_AUTOGROUP ++ struct autogroup *autogroup; ++#endif + /* + * Cumulative resource counters for dead threads in the group, + * and for reaped dead child processes forked by this group. +@@ -1931,6 +1936,20 @@ int sched_rt_handler(struct ctl_table *t + + extern unsigned int sysctl_sched_compat_yield; + ++#ifdef CONFIG_SCHED_AUTOGROUP ++extern unsigned int sysctl_sched_autogroup_enabled; ++ ++extern void sched_autogroup_create_attach(struct task_struct *p); ++extern void sched_autogroup_detach(struct task_struct *p); ++extern void sched_autogroup_fork(struct signal_struct *sig); ++extern void sched_autogroup_exit(struct signal_struct *sig); ++#else ++static inline void sched_autogroup_create_attach(struct task_struct *p) { } ++static inline void sched_autogroup_detach(struct task_struct *p) { } ++static inline void sched_autogroup_fork(struct signal_struct *sig) { } ++static inline void sched_autogroup_exit(struct signal_struct *sig) { } ++#endif ++ + #ifdef CONFIG_RT_MUTEXES + extern int rt_mutex_getprio(struct task_struct *p); + extern void rt_mutex_setprio(struct task_struct *p, int prio); +Index: linux-2.6/kernel/sched.c +=================================================================== +--- linux-2.6.orig/kernel/sched.c ++++ linux-2.6/kernel/sched.c +@@ -78,6 +78,7 @@ + + #include "sched_cpupri.h" + #include "workqueue_sched.h" ++#include "sched_autogroup.h" + + #define CREATE_TRACE_POINTS + #include +@@ -605,11 +606,14 @@ static inline int cpu_of(struct rq *rq) + */ + static inline struct task_group *task_group(struct task_struct *p) + { ++ struct task_group *tg; + struct cgroup_subsys_state *css; + + css = task_subsys_state_check(p, cpu_cgroup_subsys_id, + lockdep_is_held(&task_rq(p)->lock)); +- return container_of(css, struct task_group, css); ++ tg = container_of(css, struct task_group, css); ++ ++ return autogroup_task_group(p, tg); + } + + /* Change a task's cfs_rq and parent entity if it moves across CPUs/groups */ +@@ -2006,6 +2010,7 @@ static void sched_irq_time_avg_update(st + #include "sched_idletask.c" + #include "sched_fair.c" + #include "sched_rt.c" ++#include "sched_autogroup.c" + #include "sched_stoptask.c" + #ifdef CONFIG_SCHED_DEBUG + # include "sched_debug.c" +@@ -7979,7 +7984,7 @@ void __init sched_init(void) + #ifdef CONFIG_CGROUP_SCHED + list_add(&init_task_group.list, &task_groups); + INIT_LIST_HEAD(&init_task_group.children); +- ++ autogroup_init(&init_task); + #endif /* CONFIG_CGROUP_SCHED */ + + #if defined CONFIG_FAIR_GROUP_SCHED && defined CONFIG_SMP +Index: linux-2.6/kernel/fork.c +=================================================================== +--- linux-2.6.orig/kernel/fork.c ++++ linux-2.6/kernel/fork.c +@@ -174,8 +174,10 @@ static inline void free_signal_struct(st + + static inline void put_signal_struct(struct signal_struct *sig) + { +- if (atomic_dec_and_test(&sig->sigcnt)) ++ if (atomic_dec_and_test(&sig->sigcnt)) { ++ sched_autogroup_exit(sig); + free_signal_struct(sig); ++ } + } + + void __put_task_struct(struct task_struct *tsk) +@@ -904,6 +906,7 @@ static int copy_signal(unsigned long clo + posix_cpu_timers_init_group(sig); + + tty_audit_fork(sig); ++ sched_autogroup_fork(sig); + + sig->oom_adj = current->signal->oom_adj; + sig->oom_score_adj = current->signal->oom_score_adj; +Index: linux-2.6/drivers/tty/tty_io.c +=================================================================== +--- linux-2.6.orig/drivers/tty/tty_io.c ++++ linux-2.6/drivers/tty/tty_io.c +@@ -3160,6 +3160,7 @@ static void __proc_set_tty(struct task_s + put_pid(tsk->signal->tty_old_pgrp); + tsk->signal->tty = tty_kref_get(tty); + tsk->signal->tty_old_pgrp = NULL; ++ sched_autogroup_create_attach(tsk); + } + + static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) +Index: linux-2.6/kernel/sched_autogroup.h +=================================================================== +--- /dev/null ++++ linux-2.6/kernel/sched_autogroup.h +@@ -0,0 +1,16 @@ ++#ifdef CONFIG_SCHED_AUTOGROUP ++ ++static inline struct task_group * ++autogroup_task_group(struct task_struct *p, struct task_group *tg); ++ ++#else /* !CONFIG_SCHED_AUTOGROUP */ ++ ++static inline void autogroup_init(struct task_struct *init_task) { } ++ ++static inline struct task_group * ++autogroup_task_group(struct task_struct *p, struct task_group *tg) ++{ ++ return tg; ++} ++ ++#endif /* CONFIG_SCHED_AUTOGROUP */ +Index: linux-2.6/kernel/sched_autogroup.c +=================================================================== +--- /dev/null ++++ linux-2.6/kernel/sched_autogroup.c +@@ -0,0 +1,150 @@ ++#ifdef CONFIG_SCHED_AUTOGROUP ++ ++unsigned int __read_mostly sysctl_sched_autogroup_enabled = 1; ++ ++struct autogroup { ++ struct kref kref; ++ struct task_group *tg; ++}; ++ ++static struct autogroup autogroup_default; ++ ++static void autogroup_init(struct task_struct *init_task) ++{ ++ autogroup_default.tg = &init_task_group; ++ kref_init(&autogroup_default.kref); ++ init_task->signal->autogroup = &autogroup_default; ++} ++ ++static inline void autogroup_destroy(struct kref *kref) ++{ ++ struct autogroup *ag = container_of(kref, struct autogroup, kref); ++ struct task_group *tg = ag->tg; ++ ++ kfree(ag); ++ sched_destroy_group(tg); ++} ++ ++static inline void autogroup_kref_put(struct autogroup *ag) ++{ ++ kref_put(&ag->kref, autogroup_destroy); ++} ++ ++static inline struct autogroup *autogroup_kref_get(struct autogroup *ag) ++{ ++ kref_get(&ag->kref); ++ return ag; ++} ++ ++static inline struct autogroup *autogroup_create(void) ++{ ++ struct autogroup *ag = kmalloc(sizeof(*ag), GFP_KERNEL); ++ ++ if (!ag) ++ goto out_fail; ++ ++ ag->tg = sched_create_group(&init_task_group); ++ kref_init(&ag->kref); ++ ++ if (!(IS_ERR(ag->tg))) ++ return ag; ++ ++out_fail: ++ if (ag) { ++ kfree(ag); ++ WARN_ON(1); ++ } else ++ WARN_ON(1); ++ ++ return autogroup_kref_get(&autogroup_default); ++} ++ ++static inline bool ++task_wants_autogroup(struct task_struct *p, struct task_group *tg) ++{ ++ if (tg != &root_task_group) ++ return false; ++ ++ if (p->sched_class != &fair_sched_class) ++ return false; ++ ++ if (p->flags & PF_EXITING) ++ return false; ++ ++ return true; ++} ++ ++static inline struct task_group * ++autogroup_task_group(struct task_struct *p, struct task_group *tg) ++{ ++ int enabled = ACCESS_ONCE(sysctl_sched_autogroup_enabled); ++ ++ if (enabled && task_wants_autogroup(p, tg)) ++ return p->signal->autogroup->tg; ++ ++ return tg; ++} ++ ++static void ++autogroup_move_group(struct task_struct *p, struct autogroup *ag) ++{ ++ struct autogroup *prev; ++ struct task_struct *t; ++ ++ prev = p->signal->autogroup; ++ if (prev == ag) ++ return; ++ ++ p->signal->autogroup = autogroup_kref_get(ag); ++ sched_move_task(p); ++ ++ rcu_read_lock(); ++ list_for_each_entry_rcu(t, &p->thread_group, thread_group) { ++ sched_move_task(t); ++ } ++ rcu_read_unlock(); ++ ++ autogroup_kref_put(prev); ++} ++ ++/* Must be called with siglock held */ ++void sched_autogroup_create_attach(struct task_struct *p) ++{ ++ struct autogroup *ag = autogroup_create(); ++ ++ autogroup_move_group(p, ag); ++ /* drop extra refrence added by autogroup_create() */ ++ autogroup_kref_put(ag); ++} ++EXPORT_SYMBOL(sched_autogroup_create_attach); ++ ++/* Must be called with siglock held. Currently has no users */ ++void sched_autogroup_detach(struct task_struct *p) ++{ ++ autogroup_move_group(p, &autogroup_default); ++} ++EXPORT_SYMBOL(sched_autogroup_detach); ++ ++void sched_autogroup_fork(struct signal_struct *sig) ++{ ++ struct sighand_struct *sighand = current->sighand; ++ ++ spin_lock(&sighand->siglock); ++ sig->autogroup = autogroup_kref_get(current->signal->autogroup); ++ spin_unlock(&sighand->siglock); ++} ++ ++void sched_autogroup_exit(struct signal_struct *sig) ++{ ++ autogroup_kref_put(sig->autogroup); ++} ++ ++static int __init setup_autogroup(char *str) ++{ ++ sysctl_sched_autogroup_enabled = 0; ++ ++ return 1; ++} ++ ++__setup("noautogroup", setup_autogroup); ++#endif +Index: linux-2.6/kernel/sysctl.c +=================================================================== +--- linux-2.6.orig/kernel/sysctl.c ++++ linux-2.6/kernel/sysctl.c +@@ -382,6 +382,17 @@ static struct ctl_table kern_table[] = { + .mode = 0644, + .proc_handler = proc_dointvec, + }, ++#ifdef CONFIG_SCHED_AUTOGROUP ++ { ++ .procname = "sched_autogroup_enabled", ++ .data = &sysctl_sched_autogroup_enabled, ++ .maxlen = sizeof(unsigned int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec, ++ .extra1 = &zero, ++ .extra2 = &one, ++ }, ++#endif + #ifdef CONFIG_PROVE_LOCKING + { + .procname = "prove_locking", +Index: linux-2.6/init/Kconfig +=================================================================== +--- linux-2.6.orig/init/Kconfig ++++ linux-2.6/init/Kconfig +@@ -728,6 +728,18 @@ config NET_NS + + endif # NAMESPACES + ++config SCHED_AUTOGROUP ++ bool "Automatic process group scheduling" ++ select CGROUPS ++ select CGROUP_SCHED ++ select FAIR_GROUP_SCHED ++ help ++ This option optimizes the scheduler for common desktop workloads by ++ automatically creating and populating task groups. This separation ++ of workloads isolates aggressive CPU burners (like build jobs) from ++ desktop applications. Task group autogeneration is currently based ++ upon task tty association. ++ + config MM_OWNER + bool + +Index: linux-2.6/Documentation/kernel-parameters.txt +=================================================================== +--- linux-2.6.orig/Documentation/kernel-parameters.txt ++++ linux-2.6/Documentation/kernel-parameters.txt +@@ -1622,6 +1622,8 @@ and is between 256 and 4096 characters. + noapic [SMP,APIC] Tells the kernel to not make use of any + IOAPICs that may be present in the system. + ++ noautogroup Disable scheduler automatic task group creation. ++ + nobats [PPC] Do not use BATs for mapping kernel lowmem + on "Classic" PPC cores. +