1#ifdef CONFIG_SCHED_AUTOGROUP 2 3#include "sched.h" 4 5#include <linux/proc_fs.h> 6#include <linux/seq_file.h> 7#include <linux/kallsyms.h> 8#include <linux/utsname.h> 9#include <linux/security.h> 10#include <linux/export.h> 11 12unsigned int __read_mostly sysctl_sched_autogroup_enabled = 1; 13static struct autogroup autogroup_default; 14static atomic_t autogroup_seq_nr; 15 16void __init autogroup_init(struct task_struct *init_task) 17{ 18 autogroup_default.tg = &root_task_group; 19 kref_init(&autogroup_default.kref); 20 init_rwsem(&autogroup_default.lock); 21 init_task->signal->autogroup = &autogroup_default; 22} 23 24void autogroup_free(struct task_group *tg) 25{ 26 kfree(tg->autogroup); 27} 28 29static inline void autogroup_destroy(struct kref *kref) 30{ 31 struct autogroup *ag = container_of(kref, struct autogroup, kref); 32 33#ifdef CONFIG_RT_GROUP_SCHED 34 /* We've redirected RT tasks to the root task group... */ 35 ag->tg->rt_se = NULL; 36 ag->tg->rt_rq = NULL; 37#endif 38 sched_offline_group(ag->tg); 39 sched_destroy_group(ag->tg); 40} 41 42static inline void autogroup_kref_put(struct autogroup *ag) 43{ 44 kref_put(&ag->kref, autogroup_destroy); 45} 46 47static inline struct autogroup *autogroup_kref_get(struct autogroup *ag) 48{ 49 kref_get(&ag->kref); 50 return ag; 51} 52 53static inline struct autogroup *autogroup_task_get(struct task_struct *p) 54{ 55 struct autogroup *ag; 56 unsigned long flags; 57 58 if (!lock_task_sighand(p, &flags)) 59 return autogroup_kref_get(&autogroup_default); 60 61 ag = autogroup_kref_get(p->signal->autogroup); 62 unlock_task_sighand(p, &flags); 63 64 return ag; 65} 66 67static inline struct autogroup *autogroup_create(void) 68{ 69 struct autogroup *ag = kzalloc(sizeof(*ag), GFP_KERNEL); 70 struct task_group *tg; 71 72 if (!ag) 73 goto out_fail; 74 75 tg = sched_create_group(&root_task_group); 76 77 if (IS_ERR(tg)) 78 goto out_free; 79 80 kref_init(&ag->kref); 81 init_rwsem(&ag->lock); 82 ag->id = atomic_inc_return(&autogroup_seq_nr); 83 ag->tg = tg; 84#ifdef CONFIG_RT_GROUP_SCHED 85 /* 86 * Autogroup RT tasks are redirected to the root task group 87 * so we don't have to move tasks around upon policy change, 88 * or flail around trying to allocate bandwidth on the fly. 89 * A bandwidth exception in __sched_setscheduler() allows 90 * the policy change to proceed. 91 */ 92 free_rt_sched_group(tg); 93 tg->rt_se = root_task_group.rt_se; 94 tg->rt_rq = root_task_group.rt_rq; 95#endif 96 tg->autogroup = ag; 97 98 sched_online_group(tg, &root_task_group); 99 return ag; 100 101out_free: 102 kfree(ag); 103out_fail: 104 if (printk_ratelimit()) { 105 printk(KERN_WARNING "autogroup_create: %s failure.\n", 106 ag ? "sched_create_group()" : "kmalloc()"); 107 } 108 109 return autogroup_kref_get(&autogroup_default); 110} 111 112bool task_wants_autogroup(struct task_struct *p, struct task_group *tg) 113{ 114 if (tg != &root_task_group) 115 return false; 116 117 /* 118 * We can only assume the task group can't go away on us if 119 * autogroup_move_group() can see us on ->thread_group list. 120 */ 121 if (p->flags & PF_EXITING) 122 return false; 123 124 return true; 125} 126 127static void 128autogroup_move_group(struct task_struct *p, struct autogroup *ag) 129{ 130 struct autogroup *prev; 131 struct task_struct *t; 132 unsigned long flags; 133 134 BUG_ON(!lock_task_sighand(p, &flags)); 135 136 prev = p->signal->autogroup; 137 if (prev == ag) { 138 unlock_task_sighand(p, &flags); 139 return; 140 } 141 142 p->signal->autogroup = autogroup_kref_get(ag); 143 144 if (!ACCESS_ONCE(sysctl_sched_autogroup_enabled)) 145 goto out; 146 147 for_each_thread(p, t) 148 sched_move_task(t); 149out: 150 unlock_task_sighand(p, &flags); 151 autogroup_kref_put(prev); 152} 153 154/* Allocates GFP_KERNEL, cannot be called under any spinlock */ 155void sched_autogroup_create_attach(struct task_struct *p) 156{ 157 struct autogroup *ag = autogroup_create(); 158 159 autogroup_move_group(p, ag); 160 /* drop extra reference added by autogroup_create() */ 161 autogroup_kref_put(ag); 162} 163EXPORT_SYMBOL(sched_autogroup_create_attach); 164 165/* Cannot be called under siglock. Currently has no users */ 166void sched_autogroup_detach(struct task_struct *p) 167{ 168 autogroup_move_group(p, &autogroup_default); 169} 170EXPORT_SYMBOL(sched_autogroup_detach); 171 172void sched_autogroup_fork(struct signal_struct *sig) 173{ 174 sig->autogroup = autogroup_task_get(current); 175} 176 177void sched_autogroup_exit(struct signal_struct *sig) 178{ 179 autogroup_kref_put(sig->autogroup); 180} 181 182static int __init setup_autogroup(char *str) 183{ 184 sysctl_sched_autogroup_enabled = 0; 185 186 return 1; 187} 188 189__setup("noautogroup", setup_autogroup); 190 191#ifdef CONFIG_PROC_FS 192 193int proc_sched_autogroup_set_nice(struct task_struct *p, int nice) 194{ 195 static unsigned long next = INITIAL_JIFFIES; 196 struct autogroup *ag; 197 int err; 198 199 if (nice < MIN_NICE || nice > MAX_NICE) 200 return -EINVAL; 201 202 err = security_task_setnice(current, nice); 203 if (err) 204 return err; 205 206 if (nice < 0 && !can_nice(current, nice)) 207 return -EPERM; 208 209 /* this is a heavy operation taking global locks.. */ 210 if (!capable(CAP_SYS_ADMIN) && time_before(jiffies, next)) 211 return -EAGAIN; 212 213 next = HZ / 10 + jiffies; 214 ag = autogroup_task_get(p); 215 216 down_write(&ag->lock); 217 err = sched_group_set_shares(ag->tg, prio_to_weight[nice + 20]); 218 if (!err) 219 ag->nice = nice; 220 up_write(&ag->lock); 221 222 autogroup_kref_put(ag); 223 224 return err; 225} 226 227void proc_sched_autogroup_show_task(struct task_struct *p, struct seq_file *m) 228{ 229 struct autogroup *ag = autogroup_task_get(p); 230 231 if (!task_group_is_autogroup(ag->tg)) 232 goto out; 233 234 down_read(&ag->lock); 235 seq_printf(m, "/autogroup-%ld nice %d\n", ag->id, ag->nice); 236 up_read(&ag->lock); 237 238out: 239 autogroup_kref_put(ag); 240} 241#endif /* CONFIG_PROC_FS */ 242 243#ifdef CONFIG_SCHED_DEBUG 244int autogroup_path(struct task_group *tg, char *buf, int buflen) 245{ 246 if (!task_group_is_autogroup(tg)) 247 return 0; 248 249 return snprintf(buf, buflen, "%s-%ld", "/autogroup", tg->autogroup->id); 250} 251#endif /* CONFIG_SCHED_DEBUG */ 252 253#endif /* CONFIG_SCHED_AUTOGROUP */ 254