static void autogroup_move_group(struct task_struct *p, struct autogroup *ag) { struct autogroup *prev; struct task_struct *t; unsigned long flags; BUG_ON(!lock_task_sighand(p, &flags)); prev = p->signal->autogroup; if (prev == ag) { unlock_task_sighand(p, &flags); return; } p->signal->autogroup = autogroup_kref_get(ag); if (!ACCESS_ONCE(sysctl_sched_autogroup_enabled)) goto out; t = p; do { sched_move_task(t); } while_each_thread(p, t); out: unlock_task_sighand(p, &flags); autogroup_kref_put(prev); }
int proc_sched_autogroup_set_nice(struct task_struct *p, int *nice) { static unsigned long next = INITIAL_JIFFIES; struct autogroup *ag; int err; if (*nice < -20 || *nice > 19) return -EINVAL; err = security_task_setnice(current, *nice); if (err) return err; if (*nice < 0 && !can_nice(current, *nice)) return -EPERM; /* this is a heavy operation taking global locks.. */ if (!capable(CAP_SYS_ADMIN) && time_before(jiffies, next)) return -EAGAIN; next = HZ / 10 + jiffies; ag = autogroup_task_get(p); down_write(&ag->lock); err = sched_group_set_shares(ag->tg, prio_to_weight[*nice + 20]); if (!err) ag->nice = *nice; up_write(&ag->lock); autogroup_kref_put(ag); return err; }
static void autogroup_move_group(struct task_struct *p, struct autogroup *ag) { struct autogroup *prev; struct task_struct *t; unsigned long flags; BUG_ON(!lock_task_sighand(p, &flags)); prev = p->signal->autogroup; if (prev == ag) { unlock_task_sighand(p, &flags); return; } p->signal->autogroup = autogroup_kref_get(ag); /* * We can't avoid sched_move_task() after we changed signal->autogroup, * this process can already run with task_group() == prev->tg or we can * race with cgroup code which can read autogroup = prev under rq->lock. * In the latter case for_each_thread() can not miss a migrating thread, * cpu_cgroup_attach() must not be possible after cgroup_exit() and it * can't be removed from thread list, we hold ->siglock. * * If an exiting thread was already removed from thread list we rely on * sched_autogroup_exit_task(). */ for_each_thread(p, t) sched_move_task(t); unlock_task_sighand(p, &flags); autogroup_kref_put(prev); }
/* Allocates GFP_KERNEL, cannot be called under any spinlock */ 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); }
void sched_autogroup_create_attach(struct task_struct *p) { struct autogroup *ag = autogroup_create(); autogroup_move_group(p, ag); autogroup_kref_put(ag); }
void proc_sched_autogroup_show_task(struct task_struct *p, struct seq_file *m) { struct autogroup *ag = autogroup_task_get(p); down_read(&ag->lock); seq_printf(m, "/autogroup-%ld nice %d\n", ag->id, ag->nice); up_read(&ag->lock); autogroup_kref_put(ag); }
void sched_autogroup_exit(struct signal_struct *sig) { autogroup_kref_put(sig->autogroup); }