diff options
-rw-r--r-- | Documentation/kernel-parameters.txt | 2 | ||||
-rw-r--r-- | fs/proc/base.c | 79 | ||||
-rw-r--r-- | include/linux/sched.h | 23 | ||||
-rw-r--r-- | init/Kconfig | 13 | ||||
-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 |
11 files changed, 409 insertions, 49 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 92e83e53148f..86820a727b0b 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -1622,6 +1622,8 @@ and is between 256 and 4096 characters. It is defined in the file | |||
1622 | noapic [SMP,APIC] Tells the kernel to not make use of any | 1622 | noapic [SMP,APIC] Tells the kernel to not make use of any |
1623 | IOAPICs that may be present in the system. | 1623 | IOAPICs that may be present in the system. |
1624 | 1624 | ||
1625 | noautogroup Disable scheduler automatic task group creation. | ||
1626 | |||
1625 | nobats [PPC] Do not use BATs for mapping kernel lowmem | 1627 | nobats [PPC] Do not use BATs for mapping kernel lowmem |
1626 | on "Classic" PPC cores. | 1628 | on "Classic" PPC cores. |
1627 | 1629 | ||
diff --git a/fs/proc/base.c b/fs/proc/base.c index f3d02ca461ec..2fa0ce29b6dc 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -1407,6 +1407,82 @@ static const struct file_operations proc_pid_sched_operations = { | |||
1407 | 1407 | ||
1408 | #endif | 1408 | #endif |
1409 | 1409 | ||
1410 | #ifdef CONFIG_SCHED_AUTOGROUP | ||
1411 | /* | ||
1412 | * Print out autogroup related information: | ||
1413 | */ | ||
1414 | static int sched_autogroup_show(struct seq_file *m, void *v) | ||
1415 | { | ||
1416 | struct inode *inode = m->private; | ||
1417 | struct task_struct *p; | ||
1418 | |||
1419 | p = get_proc_task(inode); | ||
1420 | if (!p) | ||
1421 | return -ESRCH; | ||
1422 | proc_sched_autogroup_show_task(p, m); | ||
1423 | |||
1424 | put_task_struct(p); | ||
1425 | |||
1426 | return 0; | ||
1427 | } | ||
1428 | |||
1429 | static ssize_t | ||
1430 | sched_autogroup_write(struct file *file, const char __user *buf, | ||
1431 | size_t count, loff_t *offset) | ||
1432 | { | ||
1433 | struct inode *inode = file->f_path.dentry->d_inode; | ||
1434 | struct task_struct *p; | ||
1435 | char buffer[PROC_NUMBUF]; | ||
1436 | long nice; | ||
1437 | int err; | ||
1438 | |||
1439 | memset(buffer, 0, sizeof(buffer)); | ||
1440 | if (count > sizeof(buffer) - 1) | ||
1441 | count = sizeof(buffer) - 1; | ||
1442 | if (copy_from_user(buffer, buf, count)) | ||
1443 | return -EFAULT; | ||
1444 | |||
1445 | err = strict_strtol(strstrip(buffer), 0, &nice); | ||
1446 | if (err) | ||
1447 | return -EINVAL; | ||
1448 | |||
1449 | p = get_proc_task(inode); | ||
1450 | if (!p) | ||
1451 | return -ESRCH; | ||
1452 | |||
1453 | err = nice; | ||
1454 | err = proc_sched_autogroup_set_nice(p, &err); | ||
1455 | if (err) | ||
1456 | count = err; | ||
1457 | |||
1458 | put_task_struct(p); | ||
1459 | |||
1460 | return count; | ||
1461 | } | ||
1462 | |||
1463 | static int sched_autogroup_open(struct inode *inode, struct file *filp) | ||
1464 | { | ||
1465 | int ret; | ||
1466 | |||
1467 | ret = single_open(filp, sched_autogroup_show, NULL); | ||
1468 | if (!ret) { | ||
1469 | struct seq_file *m = filp->private_data; | ||
1470 | |||
1471 | m->private = inode; | ||
1472 | } | ||
1473 | return ret; | ||
1474 | } | ||
1475 | |||
1476 | static const struct file_operations proc_pid_sched_autogroup_operations = { | ||
1477 | .open = sched_autogroup_open, | ||
1478 | .read = seq_read, | ||
1479 | .write = sched_autogroup_write, | ||
1480 | .llseek = seq_lseek, | ||
1481 | .release = single_release, | ||
1482 | }; | ||
1483 | |||
1484 | #endif /* CONFIG_SCHED_AUTOGROUP */ | ||
1485 | |||
1410 | static ssize_t comm_write(struct file *file, const char __user *buf, | 1486 | static ssize_t comm_write(struct file *file, const char __user *buf, |
1411 | size_t count, loff_t *offset) | 1487 | size_t count, loff_t *offset) |
1412 | { | 1488 | { |
@@ -2733,6 +2809,9 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2733 | #ifdef CONFIG_SCHED_DEBUG | 2809 | #ifdef CONFIG_SCHED_DEBUG |
2734 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), | 2810 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), |
2735 | #endif | 2811 | #endif |
2812 | #ifdef CONFIG_SCHED_AUTOGROUP | ||
2813 | REG("autogroup", S_IRUGO|S_IWUSR, proc_pid_sched_autogroup_operations), | ||
2814 | #endif | ||
2736 | REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), | 2815 | REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), |
2737 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK | 2816 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK |
2738 | INF("syscall", S_IRUSR, proc_pid_syscall), | 2817 | INF("syscall", S_IRUSR, proc_pid_syscall), |
diff --git a/include/linux/sched.h b/include/linux/sched.h index a5b92c70c737..9c2d46da486e 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -509,6 +509,8 @@ struct thread_group_cputimer { | |||
509 | spinlock_t lock; | 509 | spinlock_t lock; |
510 | }; | 510 | }; |
511 | 511 | ||
512 | struct autogroup; | ||
513 | |||
512 | /* | 514 | /* |
513 | * NOTE! "signal_struct" does not have it's own | 515 | * NOTE! "signal_struct" does not have it's own |
514 | * locking, because a shared signal_struct always | 516 | * locking, because a shared signal_struct always |
@@ -576,6 +578,9 @@ struct signal_struct { | |||
576 | 578 | ||
577 | struct tty_struct *tty; /* NULL if no tty */ | 579 | struct tty_struct *tty; /* NULL if no tty */ |
578 | 580 | ||
581 | #ifdef CONFIG_SCHED_AUTOGROUP | ||
582 | struct autogroup *autogroup; | ||
583 | #endif | ||
579 | /* | 584 | /* |
580 | * Cumulative resource counters for dead threads in the group, | 585 | * Cumulative resource counters for dead threads in the group, |
581 | * and for reaped dead child processes forked by this group. | 586 | * and for reaped dead child processes forked by this group. |
@@ -1927,6 +1932,24 @@ int sched_rt_handler(struct ctl_table *table, int write, | |||
1927 | 1932 | ||
1928 | extern unsigned int sysctl_sched_compat_yield; | 1933 | extern unsigned int sysctl_sched_compat_yield; |
1929 | 1934 | ||
1935 | #ifdef CONFIG_SCHED_AUTOGROUP | ||
1936 | extern unsigned int sysctl_sched_autogroup_enabled; | ||
1937 | |||
1938 | extern void sched_autogroup_create_attach(struct task_struct *p); | ||
1939 | extern void sched_autogroup_detach(struct task_struct *p); | ||
1940 | extern void sched_autogroup_fork(struct signal_struct *sig); | ||
1941 | extern void sched_autogroup_exit(struct signal_struct *sig); | ||
1942 | #ifdef CONFIG_PROC_FS | ||
1943 | extern void proc_sched_autogroup_show_task(struct task_struct *p, struct seq_file *m); | ||
1944 | extern int proc_sched_autogroup_set_nice(struct task_struct *p, int *nice); | ||
1945 | #endif | ||
1946 | #else | ||
1947 | static inline void sched_autogroup_create_attach(struct task_struct *p) { } | ||
1948 | static inline void sched_autogroup_detach(struct task_struct *p) { } | ||
1949 | static inline void sched_autogroup_fork(struct signal_struct *sig) { } | ||
1950 | static inline void sched_autogroup_exit(struct signal_struct *sig) { } | ||
1951 | #endif | ||
1952 | |||
1930 | #ifdef CONFIG_RT_MUTEXES | 1953 | #ifdef CONFIG_RT_MUTEXES |
1931 | extern int rt_mutex_getprio(struct task_struct *p); | 1954 | extern int rt_mutex_getprio(struct task_struct *p); |
1932 | extern void rt_mutex_setprio(struct task_struct *p, int prio); | 1955 | extern void rt_mutex_setprio(struct task_struct *p, int prio); |
diff --git a/init/Kconfig b/init/Kconfig index 88c10468db46..f1bba0a1b051 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
@@ -728,6 +728,19 @@ config NET_NS | |||
728 | 728 | ||
729 | endif # NAMESPACES | 729 | endif # NAMESPACES |
730 | 730 | ||
731 | config SCHED_AUTOGROUP | ||
732 | bool "Automatic process group scheduling" | ||
733 | select EVENTFD | ||
734 | select CGROUPS | ||
735 | select CGROUP_SCHED | ||
736 | select FAIR_GROUP_SCHED | ||
737 | help | ||
738 | This option optimizes the scheduler for common desktop workloads by | ||
739 | automatically creating and populating task groups. This separation | ||
740 | of workloads isolates aggressive CPU burners (like build jobs) from | ||
741 | desktop applications. Task group autogeneration is currently based | ||
742 | upon task session. | ||
743 | |||
731 | config MM_OWNER | 744 | config MM_OWNER |
732 | bool | 745 | bool |
733 | 746 | ||
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 | autogroup_move_group(struct task_struct *p, struct autogroup *ag) | ||
108 | { | ||
109 | struct autogroup *prev; | ||
110 | struct task_struct *t; | ||
111 | unsigned long flags; | ||
112 | |||
113 | BUG_ON(!lock_task_sighand(p, &flags)); | ||
114 | |||
115 | prev = p->signal->autogroup; | ||
116 | if (prev == ag) { | ||
117 | unlock_task_sighand(p, &flags); | ||
118 | return; | ||
119 | } | ||
120 | |||
121 | p->signal->autogroup = autogroup_kref_get(ag); | ||
122 | |||
123 | t = p; | ||
124 | do { | ||
125 | sched_move_task(t); | ||
126 | } while_each_thread(p, t); | ||
127 | |||
128 | unlock_task_sighand(p, &flags); | ||
129 | autogroup_kref_put(prev); | ||
130 | } | ||
131 | |||
132 | /* Allocates GFP_KERNEL, cannot be called under any spinlock */ | ||
133 | void sched_autogroup_create_attach(struct task_struct *p) | ||
134 | { | ||
135 | struct autogroup *ag = autogroup_create(); | ||
136 | |||
137 | autogroup_move_group(p, ag); | ||
138 | /* drop extra refrence added by autogroup_create() */ | ||
139 | autogroup_kref_put(ag); | ||
140 | } | ||
141 | EXPORT_SYMBOL(sched_autogroup_create_attach); | ||
142 | |||
143 | /* Cannot be called under siglock. Currently has no users */ | ||
144 | void sched_autogroup_detach(struct task_struct *p) | ||
145 | { | ||
146 | autogroup_move_group(p, &autogroup_default); | ||
147 | } | ||
148 | EXPORT_SYMBOL(sched_autogroup_detach); | ||
149 | |||
150 | void sched_autogroup_fork(struct signal_struct *sig) | ||
151 | { | ||
152 | struct task_struct *p = current; | ||
153 | |||
154 | spin_lock_irq(&p->sighand->siglock); | ||
155 | sig->autogroup = autogroup_kref_get(p->signal->autogroup); | ||
156 | spin_unlock_irq(&p->sighand->siglock); | ||
157 | } | ||
158 | |||
159 | void sched_autogroup_exit(struct signal_struct *sig) | ||
160 | { | ||
161 | autogroup_kref_put(sig->autogroup); | ||
162 | } | ||
163 | |||
164 | static int __init setup_autogroup(char *str) | ||
165 | { | ||
166 | sysctl_sched_autogroup_enabled = 0; | ||
167 | |||
168 | return 1; | ||
169 | } | ||
170 | |||
171 | __setup("noautogroup", setup_autogroup); | ||
172 | |||
173 | #ifdef CONFIG_PROC_FS | ||
174 | |||
175 | /* Called with siglock held. */ | ||
176 | int proc_sched_autogroup_set_nice(struct task_struct *p, int *nice) | ||
177 | { | ||
178 | static unsigned long next = INITIAL_JIFFIES; | ||
179 | struct autogroup *ag; | ||
180 | int err; | ||
181 | |||
182 | if (*nice < -20 || *nice > 19) | ||
183 | return -EINVAL; | ||
184 | |||
185 | err = security_task_setnice(current, *nice); | ||
186 | if (err) | ||
187 | return err; | ||
188 | |||
189 | if (*nice < 0 && !can_nice(current, *nice)) | ||
190 | return -EPERM; | ||
191 | |||
192 | /* this is a heavy operation taking global locks.. */ | ||
193 | if (!capable(CAP_SYS_ADMIN) && time_before(jiffies, next)) | ||
194 | return -EAGAIN; | ||
195 | |||
196 | next = HZ / 10 + jiffies; | ||
197 | ag = autogroup_kref_get(p->signal->autogroup); | ||
198 | |||
199 | down_write(&ag->lock); | ||
200 | err = sched_group_set_shares(ag->tg, prio_to_weight[*nice + 20]); | ||
201 | if (!err) | ||
202 | ag->nice = *nice; | ||
203 | up_write(&ag->lock); | ||
204 | |||
205 | autogroup_kref_put(ag); | ||
206 | |||
207 | return err; | ||
208 | } | ||
209 | |||
210 | void proc_sched_autogroup_show_task(struct task_struct *p, struct seq_file *m) | ||
211 | { | ||
212 | struct autogroup *ag = autogroup_kref_get(p->signal->autogroup); | ||
213 | |||
214 | down_read(&ag->lock); | ||
215 | seq_printf(m, "/autogroup-%ld nice %d\n", ag->id, ag->nice); | ||
216 | up_read(&ag->lock); | ||
217 | |||
218 | autogroup_kref_put(ag); | ||
219 | } | ||
220 | #endif /* CONFIG_PROC_FS */ | ||
221 | |||
222 | #ifdef CONFIG_SCHED_DEBUG | ||
223 | static inline int autogroup_path(struct task_group *tg, char *buf, int buflen) | ||
224 | { | ||
225 | return snprintf(buf, buflen, "%s-%ld", "/autogroup", tg->autogroup->id); | ||
226 | } | ||
227 | #endif /* CONFIG_SCHED_DEBUG */ | ||
228 | |||
229 | #endif /* CONFIG_SCHED_AUTOGROUP */ | ||
diff --git a/kernel/sched_autogroup.h b/kernel/sched_autogroup.h new file mode 100644 index 000000000000..5358e241cb20 --- /dev/null +++ b/kernel/sched_autogroup.h | |||
@@ -0,0 +1,32 @@ | |||
1 | #ifdef CONFIG_SCHED_AUTOGROUP | ||
2 | |||
3 | struct autogroup { | ||
4 | struct kref kref; | ||
5 | struct task_group *tg; | ||
6 | struct rw_semaphore lock; | ||
7 | unsigned long id; | ||
8 | int nice; | ||
9 | }; | ||
10 | |||
11 | static inline struct task_group * | ||
12 | autogroup_task_group(struct task_struct *p, struct task_group *tg); | ||
13 | |||
14 | #else /* !CONFIG_SCHED_AUTOGROUP */ | ||
15 | |||
16 | static inline void autogroup_init(struct task_struct *init_task) { } | ||
17 | static inline void autogroup_free(struct task_group *tg) { } | ||
18 | |||
19 | static inline struct task_group * | ||
20 | autogroup_task_group(struct task_struct *p, struct task_group *tg) | ||
21 | { | ||
22 | return tg; | ||
23 | } | ||
24 | |||
25 | #ifdef CONFIG_SCHED_DEBUG | ||
26 | static inline int autogroup_path(struct task_group *tg, char *buf, int buflen) | ||
27 | { | ||
28 | return 0; | ||
29 | } | ||
30 | #endif | ||
31 | |||
32 | #endif /* CONFIG_SCHED_AUTOGROUP */ | ||
diff --git a/kernel/sched_debug.c b/kernel/sched_debug.c index e95b77414a99..1dfae3d014b5 100644 --- a/kernel/sched_debug.c +++ b/kernel/sched_debug.c | |||
@@ -54,8 +54,7 @@ static unsigned long nsec_low(unsigned long long nsec) | |||
54 | #define SPLIT_NS(x) nsec_high(x), nsec_low(x) | 54 | #define SPLIT_NS(x) nsec_high(x), nsec_low(x) |
55 | 55 | ||
56 | #ifdef CONFIG_FAIR_GROUP_SCHED | 56 | #ifdef CONFIG_FAIR_GROUP_SCHED |
57 | static void print_cfs_group_stats(struct seq_file *m, int cpu, | 57 | static void print_cfs_group_stats(struct seq_file *m, int cpu, struct task_group *tg) |
58 | struct task_group *tg) | ||
59 | { | 58 | { |
60 | struct sched_entity *se = tg->se[cpu]; | 59 | struct sched_entity *se = tg->se[cpu]; |
61 | if (!se) | 60 | if (!se) |
@@ -110,16 +109,6 @@ print_task(struct seq_file *m, struct rq *rq, struct task_struct *p) | |||
110 | 0LL, 0LL, 0LL, 0L, 0LL, 0L, 0LL, 0L); | 109 | 0LL, 0LL, 0LL, 0L, 0LL, 0L, 0LL, 0L); |
111 | #endif | 110 | #endif |
112 | 111 | ||
113 | #ifdef CONFIG_CGROUP_SCHED | ||
114 | { | ||
115 | char path[64]; | ||
116 | |||
117 | rcu_read_lock(); | ||
118 | cgroup_path(task_group(p)->css.cgroup, path, sizeof(path)); | ||
119 | rcu_read_unlock(); | ||
120 | SEQ_printf(m, " %s", path); | ||
121 | } | ||
122 | #endif | ||
123 | SEQ_printf(m, "\n"); | 112 | SEQ_printf(m, "\n"); |
124 | } | 113 | } |
125 | 114 | ||
@@ -147,19 +136,6 @@ static void print_rq(struct seq_file *m, struct rq *rq, int rq_cpu) | |||
147 | read_unlock_irqrestore(&tasklist_lock, flags); | 136 | read_unlock_irqrestore(&tasklist_lock, flags); |
148 | } | 137 | } |
149 | 138 | ||
150 | #if defined(CONFIG_CGROUP_SCHED) && \ | ||
151 | (defined(CONFIG_FAIR_GROUP_SCHED) || defined(CONFIG_RT_GROUP_SCHED)) | ||
152 | static void task_group_path(struct task_group *tg, char *buf, int buflen) | ||
153 | { | ||
154 | /* may be NULL if the underlying cgroup isn't fully-created yet */ | ||
155 | if (!tg->css.cgroup) { | ||
156 | buf[0] = '\0'; | ||
157 | return; | ||
158 | } | ||
159 | cgroup_path(tg->css.cgroup, buf, buflen); | ||
160 | } | ||
161 | #endif | ||
162 | |||
163 | void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq) | 139 | void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq) |
164 | { | 140 | { |
165 | s64 MIN_vruntime = -1, min_vruntime, max_vruntime = -1, | 141 | s64 MIN_vruntime = -1, min_vruntime, max_vruntime = -1, |
@@ -168,16 +144,7 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq) | |||
168 | struct sched_entity *last; | 144 | struct sched_entity *last; |
169 | unsigned long flags; | 145 | unsigned long flags; |
170 | 146 | ||
171 | #if defined(CONFIG_CGROUP_SCHED) && defined(CONFIG_FAIR_GROUP_SCHED) | ||
172 | char path[128]; | ||
173 | struct task_group *tg = cfs_rq->tg; | ||
174 | |||
175 | task_group_path(tg, path, sizeof(path)); | ||
176 | |||
177 | SEQ_printf(m, "\ncfs_rq[%d]:%s\n", cpu, path); | ||
178 | #else | ||
179 | SEQ_printf(m, "\ncfs_rq[%d]:\n", cpu); | 147 | SEQ_printf(m, "\ncfs_rq[%d]:\n", cpu); |
180 | #endif | ||
181 | SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "exec_clock", | 148 | SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "exec_clock", |
182 | SPLIT_NS(cfs_rq->exec_clock)); | 149 | SPLIT_NS(cfs_rq->exec_clock)); |
183 | 150 | ||
@@ -215,7 +182,7 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq) | |||
215 | SEQ_printf(m, " .%-30s: %ld\n", "load_contrib", | 182 | SEQ_printf(m, " .%-30s: %ld\n", "load_contrib", |
216 | cfs_rq->load_contribution); | 183 | cfs_rq->load_contribution); |
217 | SEQ_printf(m, " .%-30s: %d\n", "load_tg", | 184 | SEQ_printf(m, " .%-30s: %d\n", "load_tg", |
218 | atomic_read(&tg->load_weight)); | 185 | atomic_read(&cfs_rq->tg->load_weight)); |
219 | #endif | 186 | #endif |
220 | 187 | ||
221 | print_cfs_group_stats(m, cpu, cfs_rq->tg); | 188 | print_cfs_group_stats(m, cpu, cfs_rq->tg); |
@@ -224,17 +191,7 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq) | |||
224 | 191 | ||
225 | void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq) | 192 | void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq) |
226 | { | 193 | { |
227 | #if defined(CONFIG_CGROUP_SCHED) && defined(CONFIG_RT_GROUP_SCHED) | ||
228 | char path[128]; | ||
229 | struct task_group *tg = rt_rq->tg; | ||
230 | |||
231 | task_group_path(tg, path, sizeof(path)); | ||
232 | |||
233 | SEQ_printf(m, "\nrt_rq[%d]:%s\n", cpu, path); | ||
234 | #else | ||
235 | SEQ_printf(m, "\nrt_rq[%d]:\n", cpu); | 194 | SEQ_printf(m, "\nrt_rq[%d]:\n", cpu); |
236 | #endif | ||
237 | |||
238 | 195 | ||
239 | #define P(x) \ | 196 | #define P(x) \ |
240 | SEQ_printf(m, " .%-30s: %Ld\n", #x, (long long)(rt_rq->x)) | 197 | SEQ_printf(m, " .%-30s: %Ld\n", #x, (long long)(rt_rq->x)) |
diff --git a/kernel/sys.c b/kernel/sys.c index 7f5a0cd296a9..2745dcdb6c6c 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -1080,8 +1080,10 @@ SYSCALL_DEFINE0(setsid) | |||
1080 | err = session; | 1080 | err = session; |
1081 | out: | 1081 | out: |
1082 | write_unlock_irq(&tasklist_lock); | 1082 | write_unlock_irq(&tasklist_lock); |
1083 | if (err > 0) | 1083 | if (err > 0) { |
1084 | proc_sid_connector(group_leader); | 1084 | proc_sid_connector(group_leader); |
1085 | sched_autogroup_create_attach(group_leader); | ||
1086 | } | ||
1085 | return err; | 1087 | return err; |
1086 | } | 1088 | } |
1087 | 1089 | ||
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index a00fdefd24ce..121e4fff03d1 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
@@ -370,6 +370,17 @@ static struct ctl_table kern_table[] = { | |||
370 | .mode = 0644, | 370 | .mode = 0644, |
371 | .proc_handler = proc_dointvec, | 371 | .proc_handler = proc_dointvec, |
372 | }, | 372 | }, |
373 | #ifdef CONFIG_SCHED_AUTOGROUP | ||
374 | { | ||
375 | .procname = "sched_autogroup_enabled", | ||
376 | .data = &sysctl_sched_autogroup_enabled, | ||
377 | .maxlen = sizeof(unsigned int), | ||
378 | .mode = 0644, | ||
379 | .proc_handler = proc_dointvec, | ||
380 | .extra1 = &zero, | ||
381 | .extra2 = &one, | ||
382 | }, | ||
383 | #endif | ||
373 | #ifdef CONFIG_PROVE_LOCKING | 384 | #ifdef CONFIG_PROVE_LOCKING |
374 | { | 385 | { |
375 | .procname = "prove_locking", | 386 | .procname = "prove_locking", |