Merge branch 'perf/urgent' into perf/core
Conflicts: kernel/events/hw_breakpoint.c Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
@@ -1845,7 +1845,7 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz
|
||||
union bpf_attr attr = {};
|
||||
int err;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN) && sysctl_unprivileged_bpf_disabled)
|
||||
if (sysctl_unprivileged_bpf_disabled && !capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
err = check_uarg_tail_zero(uattr, sizeof(attr), size);
|
||||
|
@@ -3183,6 +3183,16 @@ static int cgroup_enable_threaded(struct cgroup *cgrp)
|
||||
if (cgroup_is_threaded(cgrp))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If @cgroup is populated or has domain controllers enabled, it
|
||||
* can't be switched. While the below cgroup_can_be_thread_root()
|
||||
* test can catch the same conditions, that's only when @parent is
|
||||
* not mixable, so let's check it explicitly.
|
||||
*/
|
||||
if (cgroup_is_populated(cgrp) ||
|
||||
cgrp->subtree_control & ~cgrp_dfl_threaded_ss_mask)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* we're joining the parent's domain, ensure its validity */
|
||||
if (!cgroup_is_valid_domain(dom_cgrp) ||
|
||||
!cgroup_can_be_thread_root(dom_cgrp))
|
||||
|
@@ -492,13 +492,9 @@ modify_user_hw_breakpoint_check(struct perf_event *bp, struct perf_event_attr *a
|
||||
* modify_user_hw_breakpoint - modify a user-space hardware breakpoint
|
||||
* @bp: the breakpoint structure to modify
|
||||
* @attr: new breakpoint attributes
|
||||
* @triggered: callback to trigger when we hit the breakpoint
|
||||
* @tsk: pointer to 'task_struct' of the process to which the address belongs
|
||||
*/
|
||||
int modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *attr)
|
||||
{
|
||||
int err;
|
||||
|
||||
/*
|
||||
* modify_user_hw_breakpoint can be invoked with IRQs disabled and hence it
|
||||
* will not be possible to raise IPIs that invoke __perf_event_disable.
|
||||
@@ -510,17 +506,14 @@ int modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *att
|
||||
else
|
||||
perf_event_disable(bp);
|
||||
|
||||
err = modify_user_hw_breakpoint_check(bp, attr, false);
|
||||
if (!attr->disabled) {
|
||||
int err = modify_user_hw_breakpoint_check(bp, attr, false);
|
||||
|
||||
if (err) {
|
||||
if (!bp->attr.disabled)
|
||||
perf_event_enable(bp);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!attr->disabled)
|
||||
if (err)
|
||||
return err;
|
||||
perf_event_enable(bp);
|
||||
bp->attr.disabled = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(modify_user_hw_breakpoint);
|
||||
|
@@ -14,6 +14,15 @@
|
||||
|
||||
static int fei_kprobe_handler(struct kprobe *kp, struct pt_regs *regs);
|
||||
|
||||
static void fei_post_handler(struct kprobe *kp, struct pt_regs *regs,
|
||||
unsigned long flags)
|
||||
{
|
||||
/*
|
||||
* A dummy post handler is required to prohibit optimizing, because
|
||||
* jump optimization does not support execution path overriding.
|
||||
*/
|
||||
}
|
||||
|
||||
struct fei_attr {
|
||||
struct list_head list;
|
||||
struct kprobe kp;
|
||||
@@ -56,6 +65,7 @@ static struct fei_attr *fei_attr_new(const char *sym, unsigned long addr)
|
||||
return NULL;
|
||||
}
|
||||
attr->kp.pre_handler = fei_kprobe_handler;
|
||||
attr->kp.post_handler = fei_post_handler;
|
||||
attr->retval = adjust_error_retval(addr, 0);
|
||||
INIT_LIST_HEAD(&attr->list);
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@
|
||||
#include <linux/jump_label_ratelimit.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <asm/sections.h>
|
||||
|
||||
#ifdef HAVE_JUMP_LABEL
|
||||
|
||||
@@ -421,15 +422,15 @@ void __init jump_label_init(void)
|
||||
cpus_read_unlock();
|
||||
}
|
||||
|
||||
/* Disable any jump label entries in __init code */
|
||||
void __init jump_label_invalidate_init(void)
|
||||
/* Disable any jump label entries in __init/__exit code */
|
||||
void __init jump_label_invalidate_initmem(void)
|
||||
{
|
||||
struct jump_entry *iter_start = __start___jump_table;
|
||||
struct jump_entry *iter_stop = __stop___jump_table;
|
||||
struct jump_entry *iter;
|
||||
|
||||
for (iter = iter_start; iter < iter_stop; iter++) {
|
||||
if (init_kernel_text(iter->code))
|
||||
if (init_section_contains((void *)(unsigned long)iter->code, 1))
|
||||
iter->code = 0;
|
||||
}
|
||||
}
|
||||
|
@@ -1082,15 +1082,16 @@ static noinline int __sched
|
||||
__mutex_lock_interruptible_slowpath(struct mutex *lock);
|
||||
|
||||
/**
|
||||
* mutex_lock_interruptible - acquire the mutex, interruptible
|
||||
* @lock: the mutex to be acquired
|
||||
* mutex_lock_interruptible() - Acquire the mutex, interruptible by signals.
|
||||
* @lock: The mutex to be acquired.
|
||||
*
|
||||
* Lock the mutex like mutex_lock(), and return 0 if the mutex has
|
||||
* been acquired or sleep until the mutex becomes available. If a
|
||||
* signal arrives while waiting for the lock then this function
|
||||
* returns -EINTR.
|
||||
* Lock the mutex like mutex_lock(). If a signal is delivered while the
|
||||
* process is sleeping, this function will return without acquiring the
|
||||
* mutex.
|
||||
*
|
||||
* This function is similar to (but not equivalent to) down_interruptible().
|
||||
* Context: Process context.
|
||||
* Return: 0 if the lock was successfully acquired or %-EINTR if a
|
||||
* signal arrived.
|
||||
*/
|
||||
int __sched mutex_lock_interruptible(struct mutex *lock)
|
||||
{
|
||||
@@ -1104,6 +1105,18 @@ int __sched mutex_lock_interruptible(struct mutex *lock)
|
||||
|
||||
EXPORT_SYMBOL(mutex_lock_interruptible);
|
||||
|
||||
/**
|
||||
* mutex_lock_killable() - Acquire the mutex, interruptible by fatal signals.
|
||||
* @lock: The mutex to be acquired.
|
||||
*
|
||||
* Lock the mutex like mutex_lock(). If a signal which will be fatal to
|
||||
* the current process is delivered while the process is sleeping, this
|
||||
* function will return without acquiring the mutex.
|
||||
*
|
||||
* Context: Process context.
|
||||
* Return: 0 if the lock was successfully acquired or %-EINTR if a
|
||||
* fatal signal arrived.
|
||||
*/
|
||||
int __sched mutex_lock_killable(struct mutex *lock)
|
||||
{
|
||||
might_sleep();
|
||||
@@ -1115,6 +1128,16 @@ int __sched mutex_lock_killable(struct mutex *lock)
|
||||
}
|
||||
EXPORT_SYMBOL(mutex_lock_killable);
|
||||
|
||||
/**
|
||||
* mutex_lock_io() - Acquire the mutex and mark the process as waiting for I/O
|
||||
* @lock: The mutex to be acquired.
|
||||
*
|
||||
* Lock the mutex like mutex_lock(). While the task is waiting for this
|
||||
* mutex, it will be accounted as being in the IO wait state by the
|
||||
* scheduler.
|
||||
*
|
||||
* Context: Process context.
|
||||
*/
|
||||
void __sched mutex_lock_io(struct mutex *lock)
|
||||
{
|
||||
int token;
|
||||
|
@@ -427,7 +427,6 @@ void *devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap)
|
||||
err_pfn_remap:
|
||||
err_radix:
|
||||
pgmap_radix_release(res, pgoff);
|
||||
devres_free(pgmap);
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
EXPORT_SYMBOL(devm_memremap_pages);
|
||||
|
@@ -4228,7 +4228,7 @@ static int modules_open(struct inode *inode, struct file *file)
|
||||
m->private = kallsyms_show_value() ? NULL : (void *)8ul;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct file_operations proc_modules_operations = {
|
||||
|
@@ -6683,13 +6683,18 @@ static int tg_cfs_schedulable_down(struct task_group *tg, void *data)
|
||||
parent_quota = parent_b->hierarchical_quota;
|
||||
|
||||
/*
|
||||
* Ensure max(child_quota) <= parent_quota, inherit when no
|
||||
* Ensure max(child_quota) <= parent_quota. On cgroup2,
|
||||
* always take the min. On cgroup1, only inherit when no
|
||||
* limit is set:
|
||||
*/
|
||||
if (quota == RUNTIME_INF)
|
||||
quota = parent_quota;
|
||||
else if (parent_quota != RUNTIME_INF && quota > parent_quota)
|
||||
return -EINVAL;
|
||||
if (cgroup_subsys_on_dfl(cpu_cgrp_subsys)) {
|
||||
quota = min(quota, parent_quota);
|
||||
} else {
|
||||
if (quota == RUNTIME_INF)
|
||||
quota = parent_quota;
|
||||
else if (parent_quota != RUNTIME_INF && quota > parent_quota)
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
cfs_b->hierarchical_quota = quota;
|
||||
|
||||
|
@@ -32,7 +32,7 @@ static DEFINE_SPINLOCK(sched_debug_lock);
|
||||
if (m) \
|
||||
seq_printf(m, x); \
|
||||
else \
|
||||
printk(x); \
|
||||
pr_cont(x); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
@@ -501,12 +501,12 @@ static void print_rq(struct seq_file *m, struct rq *rq, int rq_cpu)
|
||||
{
|
||||
struct task_struct *g, *p;
|
||||
|
||||
SEQ_printf(m,
|
||||
"\nrunnable tasks:\n"
|
||||
" S task PID tree-key switches prio"
|
||||
" wait-time sum-exec sum-sleep\n"
|
||||
"-------------------------------------------------------"
|
||||
"----------------------------------------------------\n");
|
||||
SEQ_printf(m, "\n");
|
||||
SEQ_printf(m, "runnable tasks:\n");
|
||||
SEQ_printf(m, " S task PID tree-key switches prio"
|
||||
" wait-time sum-exec sum-sleep\n");
|
||||
SEQ_printf(m, "-------------------------------------------------------"
|
||||
"----------------------------------------------------\n");
|
||||
|
||||
rcu_read_lock();
|
||||
for_each_process_thread(g, p) {
|
||||
@@ -527,9 +527,11 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
|
||||
unsigned long flags;
|
||||
|
||||
#ifdef CONFIG_FAIR_GROUP_SCHED
|
||||
SEQ_printf(m, "\ncfs_rq[%d]:%s\n", cpu, task_group_path(cfs_rq->tg));
|
||||
SEQ_printf(m, "\n");
|
||||
SEQ_printf(m, "cfs_rq[%d]:%s\n", cpu, task_group_path(cfs_rq->tg));
|
||||
#else
|
||||
SEQ_printf(m, "\ncfs_rq[%d]:\n", cpu);
|
||||
SEQ_printf(m, "\n");
|
||||
SEQ_printf(m, "cfs_rq[%d]:\n", cpu);
|
||||
#endif
|
||||
SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "exec_clock",
|
||||
SPLIT_NS(cfs_rq->exec_clock));
|
||||
@@ -595,9 +597,11 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
|
||||
void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq)
|
||||
{
|
||||
#ifdef CONFIG_RT_GROUP_SCHED
|
||||
SEQ_printf(m, "\nrt_rq[%d]:%s\n", cpu, task_group_path(rt_rq->tg));
|
||||
SEQ_printf(m, "\n");
|
||||
SEQ_printf(m, "rt_rq[%d]:%s\n", cpu, task_group_path(rt_rq->tg));
|
||||
#else
|
||||
SEQ_printf(m, "\nrt_rq[%d]:\n", cpu);
|
||||
SEQ_printf(m, "\n");
|
||||
SEQ_printf(m, "rt_rq[%d]:\n", cpu);
|
||||
#endif
|
||||
|
||||
#define P(x) \
|
||||
@@ -624,7 +628,8 @@ void print_dl_rq(struct seq_file *m, int cpu, struct dl_rq *dl_rq)
|
||||
{
|
||||
struct dl_bw *dl_bw;
|
||||
|
||||
SEQ_printf(m, "\ndl_rq[%d]:\n", cpu);
|
||||
SEQ_printf(m, "\n");
|
||||
SEQ_printf(m, "dl_rq[%d]:\n", cpu);
|
||||
|
||||
#define PU(x) \
|
||||
SEQ_printf(m, " .%-30s: %lu\n", #x, (unsigned long)(dl_rq->x))
|
||||
|
@@ -50,6 +50,7 @@
|
||||
#include <linux/export.h>
|
||||
#include <linux/hashtable.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/nospec.h>
|
||||
|
||||
#include "timekeeping.h"
|
||||
#include "posix-timers.h"
|
||||
@@ -1346,11 +1347,15 @@ static const struct k_clock * const posix_clocks[] = {
|
||||
|
||||
static const struct k_clock *clockid_to_kclock(const clockid_t id)
|
||||
{
|
||||
if (id < 0)
|
||||
clockid_t idx = id;
|
||||
|
||||
if (id < 0) {
|
||||
return (id & CLOCKFD_MASK) == CLOCKFD ?
|
||||
&clock_posix_dynamic : &clock_posix_cpu;
|
||||
}
|
||||
|
||||
if (id >= ARRAY_SIZE(posix_clocks) || !posix_clocks[id])
|
||||
if (id >= ARRAY_SIZE(posix_clocks))
|
||||
return NULL;
|
||||
return posix_clocks[id];
|
||||
|
||||
return posix_clocks[array_index_nospec(idx, ARRAY_SIZE(posix_clocks))];
|
||||
}
|
||||
|
@@ -661,32 +661,6 @@ static const struct bpf_func_proto bpf_get_stackid_proto_tp = {
|
||||
.arg3_type = ARG_ANYTHING,
|
||||
};
|
||||
|
||||
BPF_CALL_3(bpf_perf_prog_read_value_tp, struct bpf_perf_event_data_kern *, ctx,
|
||||
struct bpf_perf_event_value *, buf, u32, size)
|
||||
{
|
||||
int err = -EINVAL;
|
||||
|
||||
if (unlikely(size != sizeof(struct bpf_perf_event_value)))
|
||||
goto clear;
|
||||
err = perf_event_read_local(ctx->event, &buf->counter, &buf->enabled,
|
||||
&buf->running);
|
||||
if (unlikely(err))
|
||||
goto clear;
|
||||
return 0;
|
||||
clear:
|
||||
memset(buf, 0, size);
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct bpf_func_proto bpf_perf_prog_read_value_proto_tp = {
|
||||
.func = bpf_perf_prog_read_value_tp,
|
||||
.gpl_only = true,
|
||||
.ret_type = RET_INTEGER,
|
||||
.arg1_type = ARG_PTR_TO_CTX,
|
||||
.arg2_type = ARG_PTR_TO_UNINIT_MEM,
|
||||
.arg3_type = ARG_CONST_SIZE,
|
||||
};
|
||||
|
||||
static const struct bpf_func_proto *tp_prog_func_proto(enum bpf_func_id func_id)
|
||||
{
|
||||
switch (func_id) {
|
||||
@@ -694,8 +668,6 @@ static const struct bpf_func_proto *tp_prog_func_proto(enum bpf_func_id func_id)
|
||||
return &bpf_perf_event_output_proto_tp;
|
||||
case BPF_FUNC_get_stackid:
|
||||
return &bpf_get_stackid_proto_tp;
|
||||
case BPF_FUNC_perf_prog_read_value:
|
||||
return &bpf_perf_prog_read_value_proto_tp;
|
||||
default:
|
||||
return tracing_func_proto(func_id);
|
||||
}
|
||||
@@ -723,6 +695,46 @@ const struct bpf_verifier_ops tracepoint_verifier_ops = {
|
||||
const struct bpf_prog_ops tracepoint_prog_ops = {
|
||||
};
|
||||
|
||||
BPF_CALL_3(bpf_perf_prog_read_value, struct bpf_perf_event_data_kern *, ctx,
|
||||
struct bpf_perf_event_value *, buf, u32, size)
|
||||
{
|
||||
int err = -EINVAL;
|
||||
|
||||
if (unlikely(size != sizeof(struct bpf_perf_event_value)))
|
||||
goto clear;
|
||||
err = perf_event_read_local(ctx->event, &buf->counter, &buf->enabled,
|
||||
&buf->running);
|
||||
if (unlikely(err))
|
||||
goto clear;
|
||||
return 0;
|
||||
clear:
|
||||
memset(buf, 0, size);
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct bpf_func_proto bpf_perf_prog_read_value_proto = {
|
||||
.func = bpf_perf_prog_read_value,
|
||||
.gpl_only = true,
|
||||
.ret_type = RET_INTEGER,
|
||||
.arg1_type = ARG_PTR_TO_CTX,
|
||||
.arg2_type = ARG_PTR_TO_UNINIT_MEM,
|
||||
.arg3_type = ARG_CONST_SIZE,
|
||||
};
|
||||
|
||||
static const struct bpf_func_proto *pe_prog_func_proto(enum bpf_func_id func_id)
|
||||
{
|
||||
switch (func_id) {
|
||||
case BPF_FUNC_perf_event_output:
|
||||
return &bpf_perf_event_output_proto_tp;
|
||||
case BPF_FUNC_get_stackid:
|
||||
return &bpf_get_stackid_proto_tp;
|
||||
case BPF_FUNC_perf_prog_read_value:
|
||||
return &bpf_perf_prog_read_value_proto;
|
||||
default:
|
||||
return tracing_func_proto(func_id);
|
||||
}
|
||||
}
|
||||
|
||||
static bool pe_prog_is_valid_access(int off, int size, enum bpf_access_type type,
|
||||
struct bpf_insn_access_aux *info)
|
||||
{
|
||||
@@ -779,7 +791,7 @@ static u32 pe_prog_convert_ctx_access(enum bpf_access_type type,
|
||||
}
|
||||
|
||||
const struct bpf_verifier_ops perf_event_verifier_ops = {
|
||||
.get_func_proto = tp_prog_func_proto,
|
||||
.get_func_proto = pe_prog_func_proto,
|
||||
.is_valid_access = pe_prog_is_valid_access,
|
||||
.convert_ctx_access = pe_prog_convert_ctx_access,
|
||||
};
|
||||
|
@@ -667,7 +667,7 @@ static int create_trace_kprobe(int argc, char **argv)
|
||||
char *symbol = NULL, *event = NULL, *group = NULL;
|
||||
int maxactive = 0;
|
||||
char *arg;
|
||||
unsigned long offset = 0;
|
||||
long offset = 0;
|
||||
void *addr = NULL;
|
||||
char buf[MAX_EVENT_NAME_LEN];
|
||||
|
||||
@@ -755,7 +755,7 @@ static int create_trace_kprobe(int argc, char **argv)
|
||||
symbol = argv[1];
|
||||
/* TODO: support .init module functions */
|
||||
ret = traceprobe_split_symbol_offset(symbol, &offset);
|
||||
if (ret) {
|
||||
if (ret || offset < 0 || offset > UINT_MAX) {
|
||||
pr_info("Failed to parse either an address or a symbol.\n");
|
||||
return ret;
|
||||
}
|
||||
|
@@ -320,7 +320,7 @@ static fetch_func_t get_fetch_size_function(const struct fetch_type *type,
|
||||
}
|
||||
|
||||
/* Split symbol and offset. */
|
||||
int traceprobe_split_symbol_offset(char *symbol, unsigned long *offset)
|
||||
int traceprobe_split_symbol_offset(char *symbol, long *offset)
|
||||
{
|
||||
char *tmp;
|
||||
int ret;
|
||||
@@ -328,13 +328,11 @@ int traceprobe_split_symbol_offset(char *symbol, unsigned long *offset)
|
||||
if (!offset)
|
||||
return -EINVAL;
|
||||
|
||||
tmp = strchr(symbol, '+');
|
||||
tmp = strpbrk(symbol, "+-");
|
||||
if (tmp) {
|
||||
/* skip sign because kstrtoul doesn't accept '+' */
|
||||
ret = kstrtoul(tmp + 1, 0, offset);
|
||||
ret = kstrtol(tmp, 0, offset);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*tmp = '\0';
|
||||
} else
|
||||
*offset = 0;
|
||||
|
@@ -365,7 +365,7 @@ extern int traceprobe_conflict_field_name(const char *name,
|
||||
extern void traceprobe_update_arg(struct probe_arg *arg);
|
||||
extern void traceprobe_free_probe_arg(struct probe_arg *arg);
|
||||
|
||||
extern int traceprobe_split_symbol_offset(char *symbol, unsigned long *offset);
|
||||
extern int traceprobe_split_symbol_offset(char *symbol, long *offset);
|
||||
|
||||
/* Sum up total data length for dynamic arraies (strings) */
|
||||
static nokprobe_inline int
|
||||
|
@@ -3018,14 +3018,6 @@ static bool __cancel_work(struct work_struct *work, bool is_dwork)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* See cancel_delayed_work()
|
||||
*/
|
||||
bool cancel_work(struct work_struct *work)
|
||||
{
|
||||
return __cancel_work(work, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* cancel_delayed_work - cancel a delayed work
|
||||
* @dwork: delayed_work to cancel
|
||||
@@ -5337,7 +5329,7 @@ int workqueue_sysfs_register(struct workqueue_struct *wq)
|
||||
|
||||
ret = device_register(&wq_dev->dev);
|
||||
if (ret) {
|
||||
kfree(wq_dev);
|
||||
put_device(&wq_dev->dev);
|
||||
wq->wq_dev = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
Reference in New Issue
Block a user