-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit f52ad2f
Showing
37 changed files
with
38,973 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# SPDX-License-Identifier: GPL-2.0 | ||
ifdef CONFIG_FUNCTION_TRACER | ||
CFLAGS_REMOVE_clock.o = $(CC_FLAGS_FTRACE) | ||
endif | ||
|
||
# These files are disabled because they produce non-interesting flaky coverage | ||
# that is not a function of syscall inputs. E.g. involuntary context switches. | ||
KCOV_INSTRUMENT := n | ||
|
||
ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y) | ||
# According to Alan Modra <[email protected]>, the -fno-omit-frame-pointer is | ||
# needed for x86 only. Why this used to be enabled for all architectures is beyond | ||
# me. I suspect most platforms don't need this, but until we know that for sure | ||
# I turn this off for IA-64 only. Andreas Schwab says it's also needed on m68k | ||
# to get a correct value for the wait-channel (WCHAN in ps). --davidm | ||
CFLAGS_core.o := $(PROFILING) -fno-omit-frame-pointer | ||
endif | ||
|
||
obj-y += core.o loadavg.o clock.o cputime.o | ||
obj-y += idle.o fair.o rt.o deadline.o | ||
obj-y += wait.o wait_bit.o swait.o completion.o | ||
|
||
obj-$(CONFIG_SMP) += cpupri.o cpudeadline.o topology.o stop_task.o pelt.o | ||
obj-$(CONFIG_SCHED_AUTOGROUP) += autogroup.o | ||
obj-$(CONFIG_SCHEDSTATS) += stats.o | ||
obj-$(CONFIG_SCHED_DEBUG) += debug.o | ||
obj-$(CONFIG_SCHED_TUNE) += tune.o | ||
obj-$(CONFIG_CGROUP_CPUACCT) += cpuacct.o | ||
obj-$(CONFIG_CPU_FREQ) += cpufreq.o | ||
obj-$(CONFIG_CPU_FREQ_GOV_SCHEDUTIL) += cpufreq_schedutil.o | ||
obj-$(CONFIG_MEMBARRIER) += membarrier.o | ||
obj-$(CONFIG_CPU_ISOLATION) += isolation.o | ||
obj-$(CONFIG_PSI) += psi.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,268 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* | ||
* Auto-group scheduling implementation: | ||
*/ | ||
#include <linux/nospec.h> | ||
#include "sched.h" | ||
|
||
unsigned int __read_mostly sysctl_sched_autogroup_enabled = 1; | ||
static struct autogroup autogroup_default; | ||
static atomic_t autogroup_seq_nr; | ||
|
||
void __init autogroup_init(struct task_struct *init_task) | ||
{ | ||
autogroup_default.tg = &root_task_group; | ||
kref_init(&autogroup_default.kref); | ||
init_rwsem(&autogroup_default.lock); | ||
init_task->signal->autogroup = &autogroup_default; | ||
} | ||
|
||
void autogroup_free(struct task_group *tg) | ||
{ | ||
kfree(tg->autogroup); | ||
} | ||
|
||
static inline void autogroup_destroy(struct kref *kref) | ||
{ | ||
struct autogroup *ag = container_of(kref, struct autogroup, kref); | ||
|
||
#ifdef CONFIG_RT_GROUP_SCHED | ||
/* We've redirected RT tasks to the root task group... */ | ||
ag->tg->rt_se = NULL; | ||
ag->tg->rt_rq = NULL; | ||
#endif | ||
sched_offline_group(ag->tg); | ||
sched_destroy_group(ag->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_task_get(struct task_struct *p) | ||
{ | ||
struct autogroup *ag; | ||
unsigned long flags; | ||
|
||
if (!lock_task_sighand(p, &flags)) | ||
return autogroup_kref_get(&autogroup_default); | ||
|
||
ag = autogroup_kref_get(p->signal->autogroup); | ||
unlock_task_sighand(p, &flags); | ||
|
||
return ag; | ||
} | ||
|
||
static inline struct autogroup *autogroup_create(void) | ||
{ | ||
struct autogroup *ag = kzalloc(sizeof(*ag), GFP_KERNEL); | ||
struct task_group *tg; | ||
|
||
if (!ag) | ||
goto out_fail; | ||
|
||
tg = sched_create_group(&root_task_group); | ||
if (IS_ERR(tg)) | ||
goto out_free; | ||
|
||
kref_init(&ag->kref); | ||
init_rwsem(&ag->lock); | ||
ag->id = atomic_inc_return(&autogroup_seq_nr); | ||
ag->tg = tg; | ||
#ifdef CONFIG_RT_GROUP_SCHED | ||
/* | ||
* Autogroup RT tasks are redirected to the root task group | ||
* so we don't have to move tasks around upon policy change, | ||
* or flail around trying to allocate bandwidth on the fly. | ||
* A bandwidth exception in __sched_setscheduler() allows | ||
* the policy change to proceed. | ||
*/ | ||
free_rt_sched_group(tg); | ||
tg->rt_se = root_task_group.rt_se; | ||
tg->rt_rq = root_task_group.rt_rq; | ||
#endif | ||
tg->autogroup = ag; | ||
|
||
sched_online_group(tg, &root_task_group); | ||
return ag; | ||
|
||
out_free: | ||
kfree(ag); | ||
out_fail: | ||
if (printk_ratelimit()) { | ||
printk(KERN_WARNING "autogroup_create: %s failure.\n", | ||
ag ? "sched_create_group()" : "kzalloc()"); | ||
} | ||
|
||
return autogroup_kref_get(&autogroup_default); | ||
} | ||
|
||
bool task_wants_autogroup(struct task_struct *p, struct task_group *tg) | ||
{ | ||
if (tg != &root_task_group) | ||
return false; | ||
/* | ||
* If we race with autogroup_move_group() the caller can use the old | ||
* value of signal->autogroup but in this case sched_move_task() will | ||
* be called again before autogroup_kref_put(). | ||
* | ||
* However, there is no way sched_autogroup_exit_task() could tell us | ||
* to avoid autogroup->tg, so we abuse PF_EXITING flag for this case. | ||
*/ | ||
if (p->flags & PF_EXITING) | ||
return false; | ||
|
||
return true; | ||
} | ||
|
||
void sched_autogroup_exit_task(struct task_struct *p) | ||
{ | ||
/* | ||
* We are going to call exit_notify() and autogroup_move_group() can't | ||
* see this thread after that: we can no longer use signal->autogroup. | ||
* See the PF_EXITING check in task_wants_autogroup(). | ||
*/ | ||
sched_move_task(p); | ||
} | ||
|
||
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 reference added by autogroup_create(): */ | ||
autogroup_kref_put(ag); | ||
} | ||
EXPORT_SYMBOL(sched_autogroup_create_attach); | ||
|
||
/* Cannot be called under siglock. 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) | ||
{ | ||
sig->autogroup = autogroup_task_get(current); | ||
} | ||
|
||
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); | ||
|
||
#ifdef CONFIG_PROC_FS | ||
|
||
int proc_sched_autogroup_set_nice(struct task_struct *p, int nice) | ||
{ | ||
static unsigned long next = INITIAL_JIFFIES; | ||
struct autogroup *ag; | ||
unsigned long shares; | ||
int err, idx; | ||
|
||
if (nice < MIN_NICE || nice > MAX_NICE) | ||
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); | ||
|
||
idx = array_index_nospec(nice + 20, 40); | ||
shares = scale_load(sched_prio_to_weight[idx]); | ||
|
||
down_write(&ag->lock); | ||
err = sched_group_set_shares(ag->tg, shares); | ||
if (!err) | ||
ag->nice = nice; | ||
up_write(&ag->lock); | ||
|
||
autogroup_kref_put(ag); | ||
|
||
return err; | ||
} | ||
|
||
void proc_sched_autogroup_show_task(struct task_struct *p, struct seq_file *m) | ||
{ | ||
struct autogroup *ag = autogroup_task_get(p); | ||
|
||
if (!task_group_is_autogroup(ag->tg)) | ||
goto out; | ||
|
||
down_read(&ag->lock); | ||
seq_printf(m, "/autogroup-%ld nice %d\n", ag->id, ag->nice); | ||
up_read(&ag->lock); | ||
|
||
out: | ||
autogroup_kref_put(ag); | ||
} | ||
#endif /* CONFIG_PROC_FS */ | ||
|
||
int autogroup_path(struct task_group *tg, char *buf, int buflen) | ||
{ | ||
if (!task_group_is_autogroup(tg)) | ||
return 0; | ||
|
||
return snprintf(buf, buflen, "%s-%ld", "/autogroup", tg->autogroup->id); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
/* SPDX-License-Identifier: GPL-2.0 */ | ||
#ifdef CONFIG_SCHED_AUTOGROUP | ||
|
||
struct autogroup { | ||
/* | ||
* Reference doesn't mean how many threads attach to this | ||
* autogroup now. It just stands for the number of tasks | ||
* which could use this autogroup. | ||
*/ | ||
struct kref kref; | ||
struct task_group *tg; | ||
struct rw_semaphore lock; | ||
unsigned long id; | ||
int nice; | ||
}; | ||
|
||
extern void autogroup_init(struct task_struct *init_task); | ||
extern void autogroup_free(struct task_group *tg); | ||
|
||
static inline bool task_group_is_autogroup(struct task_group *tg) | ||
{ | ||
return !!tg->autogroup; | ||
} | ||
|
||
extern bool task_wants_autogroup(struct task_struct *p, struct task_group *tg); | ||
|
||
static inline struct task_group * | ||
autogroup_task_group(struct task_struct *p, struct task_group *tg) | ||
{ | ||
int enabled = READ_ONCE(sysctl_sched_autogroup_enabled); | ||
|
||
if (enabled && task_wants_autogroup(p, tg)) | ||
return p->signal->autogroup->tg; | ||
|
||
return tg; | ||
} | ||
|
||
extern int autogroup_path(struct task_group *tg, char *buf, int buflen); | ||
|
||
#else /* !CONFIG_SCHED_AUTOGROUP */ | ||
|
||
static inline void autogroup_init(struct task_struct *init_task) { } | ||
static inline void autogroup_free(struct task_group *tg) { } | ||
static inline bool task_group_is_autogroup(struct task_group *tg) | ||
{ | ||
return 0; | ||
} | ||
|
||
static inline struct task_group * | ||
autogroup_task_group(struct task_struct *p, struct task_group *tg) | ||
{ | ||
return tg; | ||
} | ||
|
||
static inline int autogroup_path(struct task_group *tg, char *buf, int buflen) | ||
{ | ||
return 0; | ||
} | ||
|
||
#endif /* CONFIG_SCHED_AUTOGROUP */ |
Oops, something went wrong.