diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/fork.c | 5 | ||||
| -rw-r--r-- | kernel/sched.c | 13 | ||||
| -rw-r--r-- | kernel/sched_autogroup.c | 229 | ||||
| -rw-r--r-- | kernel/sched_autogroup.h | 32 | ||||
| -rw-r--r-- | kernel/sched_debug.c | 47 | ||||
| -rw-r--r-- | kernel/sys.c | 4 | ||||
| -rw-r--r-- | kernel/sysctl.c | 11 |
7 files changed, 292 insertions, 49 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index 3b159c5991b7..b6f2475f1e83 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
| @@ -174,8 +174,10 @@ static inline void free_signal_struct(struct signal_struct *sig) | |||
| 174 | 174 | ||
| 175 | static inline void put_signal_struct(struct signal_struct *sig) | 175 | static inline void put_signal_struct(struct signal_struct *sig) |
| 176 | { | 176 | { |
| 177 | if (atomic_dec_and_test(&sig->sigcnt)) | 177 | if (atomic_dec_and_test(&sig->sigcnt)) { |
| 178 | sched_autogroup_exit(sig); | ||
| 178 | free_signal_struct(sig); | 179 | free_signal_struct(sig); |
| 180 | } | ||
| 179 | } | 181 | } |
| 180 | 182 | ||
| 181 | void __put_task_struct(struct task_struct *tsk) | 183 | void __put_task_struct(struct task_struct *tsk) |
| @@ -904,6 +906,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) | |||
| 904 | posix_cpu_timers_init_group(sig); | 906 | posix_cpu_timers_init_group(sig); |
| 905 | 907 | ||
| 906 | tty_audit_fork(sig); | 908 | tty_audit_fork(sig); |
| 909 | sched_autogroup_fork(sig); | ||
| 907 | 910 | ||
| 908 | sig->oom_adj = current->signal->oom_adj; | 911 | sig->oom_adj = current->signal->oom_adj; |
| 909 | sig->oom_score_adj = current->signal->oom_score_adj; | 912 | sig->oom_score_adj = current->signal->oom_score_adj; |
diff --git a/kernel/sched.c b/kernel/sched.c index 66ef5790d932..b646dad4a40e 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
| @@ -79,6 +79,7 @@ | |||
| 79 | 79 | ||
| 80 | #include "sched_cpupri.h" | 80 | #include "sched_cpupri.h" |
| 81 | #include "workqueue_sched.h" | 81 | #include "workqueue_sched.h" |
| 82 | #include "sched_autogroup.h" | ||
| 82 | 83 | ||
| 83 | #define CREATE_TRACE_POINTS | 84 | #define CREATE_TRACE_POINTS |
| 84 | #include <trace/events/sched.h> | 85 | #include <trace/events/sched.h> |
| @@ -271,6 +272,10 @@ struct task_group { | |||
| 271 | struct task_group *parent; | 272 | struct task_group *parent; |
| 272 | struct list_head siblings; | 273 | struct list_head siblings; |
| 273 | struct list_head children; | 274 | struct list_head children; |
| 275 | |||
| 276 | #ifdef CONFIG_SCHED_AUTOGROUP | ||
| 277 | struct autogroup *autogroup; | ||
| 278 | #endif | ||
| 274 | }; | 279 | }; |
| 275 | 280 | ||
| 276 | #define root_task_group init_task_group | 281 | #define root_task_group init_task_group |
| @@ -603,11 +608,14 @@ static inline int cpu_of(struct rq *rq) | |||
| 603 | */ | 608 | */ |
| 604 | static inline struct task_group *task_group(struct task_struct *p) | 609 | static inline struct task_group *task_group(struct task_struct *p) |
| 605 | { | 610 | { |
| 611 | struct task_group *tg; | ||
| 606 | struct cgroup_subsys_state *css; | 612 | struct cgroup_subsys_state *css; |
| 607 | 613 | ||
| 608 | css = task_subsys_state_check(p, cpu_cgroup_subsys_id, | 614 | css = task_subsys_state_check(p, cpu_cgroup_subsys_id, |
| 609 | lockdep_is_held(&task_rq(p)->lock)); | 615 | lockdep_is_held(&task_rq(p)->lock)); |
| 610 | return container_of(css, struct task_group, css); | 616 | tg = container_of(css, struct task_group, css); |
| 617 | |||
| 618 | return autogroup_task_group(p, tg); | ||
| 611 | } | 619 | } |
| 612 | 620 | ||
| 613 | /* Change a task's cfs_rq and parent entity if it moves across CPUs/groups */ | 621 | /* Change a task's cfs_rq and parent entity if it moves across CPUs/groups */ |
| @@ -1869,6 +1877,7 @@ static void sched_irq_time_avg_update(struct rq *rq, u64 curr_irq_time) { } | |||
| 1869 | #include "sched_idletask.c" | 1877 | #include "sched_idletask.c" |
| 1870 | #include "sched_fair.c" | 1878 | #include "sched_fair.c" |
| 1871 | #include "sched_rt.c" | 1879 | #include "sched_rt.c" |
| 1880 | #include "sched_autogroup.c" | ||
| 1872 | #include "sched_stoptask.c" | 1881 | #include "sched_stoptask.c" |
| 1873 | #ifdef CONFIG_SCHED_DEBUG | 1882 | #ifdef CONFIG_SCHED_DEBUG |
| 1874 | # include "sched_debug.c" | 1883 | # include "sched_debug.c" |
| @@ -7750,7 +7759,7 @@ void __init sched_init(void) | |||
| 7750 | #ifdef CONFIG_CGROUP_SCHED | 7759 | #ifdef CONFIG_CGROUP_SCHED |
| 7751 | list_add(&init_task_group.list, &task_groups); | 7760 | list_add(&init_task_group.list, &task_groups); |
| 7752 | INIT_LIST_HEAD(&init_task_group.children); | 7761 | INIT_LIST_HEAD(&init_task_group.children); |
| 7753 | 7762 | autogroup_init(&init_task); | |
| 7754 | #endif /* CONFIG_CGROUP_SCHED */ | 7763 | #endif /* CONFIG_CGROUP_SCHED */ |
| 7755 | 7764 | ||
| 7756 | for_each_possible_cpu(i) { | 7765 | for_each_possible_cpu(i) { |
diff --git a/kernel/sched_autogroup.c b/kernel/sched_autogroup.c new file mode 100644 index 000000000000..57a7ac286a02 --- /dev/null +++ b/kernel/sched_autogroup.c | |||
| @@ -0,0 +1,229 @@ | |||
| 1 | #ifdef CONFIG_SCHED_AUTOGROUP | ||
| 2 | |||
| 3 | #include <linux/proc_fs.h> | ||
| 4 | #include <linux/seq_file.h> | ||
| 5 | #include <linux/kallsyms.h> | ||
| 6 | #include <linux/utsname.h> | ||
| 7 | |||
| 8 | unsigned int __read_mostly sysctl_sched_autogroup_enabled = 1; | ||
| 9 | static struct autogroup autogroup_default; | ||
| 10 | static atomic_t autogroup_seq_nr; | ||
| 11 | |||
| 12 | static void autogroup_init(struct task_struct *init_task) | ||
| 13 | { | ||
| 14 | autogroup_default.tg = &init_task_group; | ||
| 15 | init_task_group.autogroup = &autogroup_default; | ||
| 16 | kref_init(&autogroup_default.kref); | ||
| 17 | init_rwsem(&autogroup_default.lock); | ||
| 18 | init_task->signal->autogroup = &autogroup_default; | ||
| 19 | } | ||
| 20 | |||
| 21 | static inline void autogroup_free(struct task_group *tg) | ||
| 22 | { | ||
| 23 | kfree(tg->autogroup); | ||
| 24 | } | ||
| 25 | |||
| 26 | static inline void autogroup_destroy(struct kref *kref) | ||
| 27 | { | ||
| 28 | struct autogroup *ag = container_of(kref, struct autogroup, kref); | ||
| 29 | |||
| 30 | sched_destroy_group(ag->tg); | ||
| 31 | } | ||
| 32 | |||
| 33 | static inline void autogroup_kref_put(struct autogroup *ag) | ||
| 34 | { | ||
| 35 | kref_put(&ag->kref, autogroup_destroy); | ||
| 36 | } | ||
| 37 | |||
| 38 | static inline struct autogroup *autogroup_kref_get(struct autogroup *ag) | ||
| 39 | { | ||
| 40 | kref_get(&ag->kref); | ||
| 41 | return ag; | ||
| 42 | } | ||
| 43 | |||
| 44 | static inline struct autogroup *autogroup_create(void) | ||
| 45 | { | ||
| 46 | struct autogroup *ag = kzalloc(sizeof(*ag), GFP_KERNEL); | ||
| 47 | struct task_group *tg; | ||
| 48 | |||
| 49 | if (!ag) | ||
| 50 | goto out_fail; | ||
| 51 | |||
| 52 | tg = sched_create_group(&init_task_group); | ||
| 53 | |||
| 54 | if (IS_ERR(tg)) | ||
| 55 | goto out_free; | ||
| 56 | |||
| 57 | kref_init(&ag->kref); | ||
| 58 | init_rwsem(&ag->lock); | ||
| 59 | ag->id = atomic_inc_return(&autogroup_seq_nr); | ||
| 60 | ag->tg = tg; | ||
| 61 | tg->autogroup = ag; | ||
| 62 | |||
| 63 | return ag; | ||
| 64 | |||
| 65 | out_free: | ||
| 66 | kfree(ag); | ||
| 67 | out_fail: | ||
| 68 | if (printk_ratelimit()) { | ||
| 69 | printk(KERN_WARNING "autogroup_create: %s failure.\n", | ||
| 70 | ag ? "sched_create_group()" : "kmalloc()"); | ||
| 71 | } | ||
| 72 | |||
| 73 | return autogroup_kref_get(&autogroup_default); | ||
| 74 | } | ||
| 75 | |||
| 76 | static inline bool | ||
| 77 | task_wants_autogroup(struct task_struct *p, struct task_group *tg) | ||
| 78 | { | ||
| 79 | if (tg != &root_task_group) | ||
| 80 | return false; | ||
| 81 | |||
| 82 | if (p->sched_class != &fair_sched_class) | ||
| 83 | return false; | ||
| 84 | |||
| 85 | /* | ||
| 86 | * We can only assume the task group can't go away on us if | ||
| 87 | * autogroup_move_group() can see us on ->thread_group list. | ||
| 88 | */ | ||
| 89 | if (p->flags & PF_EXITING) | ||
| 90 | return false; | ||
| 91 | |||
| 92 | return true; | ||
| 93 | } | ||
| 94 | |||
| 95 | static inline struct task_group * | ||
| 96 | autogroup_task_group(struct task_struct *p, struct task_group *tg) | ||
| 97 | { | ||
| 98 | int enabled = ACCESS_ONCE(sysctl_sched_autogroup_enabled); | ||
| 99 | |||
| 100 | if (enabled && task_wants_autogroup(p, tg)) | ||
| 101 | return p->signal->autogroup->tg; | ||
| 102 | |||
| 103 | return tg; | ||
| 104 | } | ||
| 105 | |||
| 106 | static void | ||
| 107 | |||
