Skip to content

Commit

Permalink
Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/…
Browse files Browse the repository at this point in the history
…linux/kernel/git/tip/tip

Pull perf updates from Thomas Gleixner:
 "Perf tool updates and kprobe fixes:

   - perf_mmap overwrite mode fixes/overhaul, prep work to get 'perf
     top' using it, making it bearable to use it in large core count
     systems such as Knights Landing/Mill Intel systems (Kan Liang)

   - s/390 now uses syscall.tbl, just like x86-64 to generate the
     syscall table id -> string tables used by 'perf trace' (Hendrik
     Brueckner)

   - Use strtoull() instead of home grown function (Andy Shevchenko)

   - Synchronize kernel ABI headers, v4.16-rc1 (Ingo Molnar)

   - Document missing 'perf data --force' option (Sangwon Hong)

   - Add perf vendor JSON metrics for ARM Cortex-A53 Processor (William
     Cohen)

   - Improve error handling and error propagation of ftrace based
     kprobes so failures when installing kprobes are not silently
     ignored and create disfunctional tracepoints"

* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (27 commits)
  kprobes: Propagate error from disarm_kprobe_ftrace()
  kprobes: Propagate error from arm_kprobe_ftrace()
  Revert "tools include s390: Grab a copy of arch/s390/include/uapi/asm/unistd.h"
  perf s390: Rework system call table creation by using syscall.tbl
  perf s390: Grab a copy of arch/s390/kernel/syscall/syscall.tbl
  tools/headers: Synchronize kernel ABI headers, v4.16-rc1
  perf test: Fix test trace+probe_libc_inet_pton.sh for s390x
  perf data: Document missing --force option
  perf tools: Substitute yet another strtoull()
  perf top: Check the latency of perf_top__mmap_read()
  perf top: Switch default mode to overwrite mode
  perf top: Remove lost events checking
  perf hists browser: Add parameter to disable lost event warning
  perf top: Add overwrite fall back
  perf evsel: Expose the perf_missing_features struct
  perf top: Check per-event overwrite term
  perf mmap: Discard legacy interface for mmap read
  perf test: Update mmap read functions for backward-ring-buffer test
  perf mmap: Introduce perf_mmap__read_event()
  perf mmap: Introduce perf_mmap__read_done()
  ...
  • Loading branch information
Linus Torvalds committed Feb 18, 2018
2 parents 2d6c4e4 + 297f923 commit 9ca2c16
Show file tree
Hide file tree
Showing 34 changed files with 1,195 additions and 628 deletions.
178 changes: 128 additions & 50 deletions kernel/kprobes.c
Original file line number Diff line number Diff line change
Expand Up @@ -978,67 +978,90 @@ static int prepare_kprobe(struct kprobe *p)
}

/* Caller must lock kprobe_mutex */
static void arm_kprobe_ftrace(struct kprobe *p)
static int arm_kprobe_ftrace(struct kprobe *p)
{
int ret;
int ret = 0;

ret = ftrace_set_filter_ip(&kprobe_ftrace_ops,
(unsigned long)p->addr, 0, 0);
WARN(ret < 0, "Failed to arm kprobe-ftrace at %p (%d)\n", p->addr, ret);
kprobe_ftrace_enabled++;
if (kprobe_ftrace_enabled == 1) {
if (ret) {
pr_debug("Failed to arm kprobe-ftrace at %p (%d)\n", p->addr, ret);
return ret;
}

if (kprobe_ftrace_enabled == 0) {
ret = register_ftrace_function(&kprobe_ftrace_ops);
WARN(ret < 0, "Failed to init kprobe-ftrace (%d)\n", ret);
if (ret) {
pr_debug("Failed to init kprobe-ftrace (%d)\n", ret);
goto err_ftrace;
}
}

kprobe_ftrace_enabled++;
return ret;

err_ftrace:
/*
* Note: Since kprobe_ftrace_ops has IPMODIFY set, and ftrace requires a
* non-empty filter_hash for IPMODIFY ops, we're safe from an accidental
* empty filter_hash which would undesirably trace all functions.
*/
ftrace_set_filter_ip(&kprobe_ftrace_ops, (unsigned long)p->addr, 1, 0);
return ret;
}

/* Caller must lock kprobe_mutex */
static void disarm_kprobe_ftrace(struct kprobe *p)
static int disarm_kprobe_ftrace(struct kprobe *p)
{
int ret;
int ret = 0;

kprobe_ftrace_enabled--;
if (kprobe_ftrace_enabled == 0) {
if (kprobe_ftrace_enabled == 1) {
ret = unregister_ftrace_function(&kprobe_ftrace_ops);
WARN(ret < 0, "Failed to init kprobe-ftrace (%d)\n", ret);
if (WARN(ret < 0, "Failed to unregister kprobe-ftrace (%d)\n", ret))
return ret;
}

kprobe_ftrace_enabled--;

ret = ftrace_set_filter_ip(&kprobe_ftrace_ops,
(unsigned long)p->addr, 1, 0);
WARN(ret < 0, "Failed to disarm kprobe-ftrace at %p (%d)\n", p->addr, ret);
return ret;
}
#else /* !CONFIG_KPROBES_ON_FTRACE */
#define prepare_kprobe(p) arch_prepare_kprobe(p)
#define arm_kprobe_ftrace(p) do {} while (0)
#define disarm_kprobe_ftrace(p) do {} while (0)
#define arm_kprobe_ftrace(p) (-ENODEV)
#define disarm_kprobe_ftrace(p) (-ENODEV)
#endif

/* Arm a kprobe with text_mutex */
static void arm_kprobe(struct kprobe *kp)
static int arm_kprobe(struct kprobe *kp)
{
if (unlikely(kprobe_ftrace(kp))) {
arm_kprobe_ftrace(kp);
return;
}
if (unlikely(kprobe_ftrace(kp)))
return arm_kprobe_ftrace(kp);

cpus_read_lock();
mutex_lock(&text_mutex);
__arm_kprobe(kp);
mutex_unlock(&text_mutex);
cpus_read_unlock();

return 0;
}

/* Disarm a kprobe with text_mutex */
static void disarm_kprobe(struct kprobe *kp, bool reopt)
static int disarm_kprobe(struct kprobe *kp, bool reopt)
{
if (unlikely(kprobe_ftrace(kp))) {
disarm_kprobe_ftrace(kp);
return;
}
if (unlikely(kprobe_ftrace(kp)))
return disarm_kprobe_ftrace(kp);

cpus_read_lock();
mutex_lock(&text_mutex);
__disarm_kprobe(kp, reopt);
mutex_unlock(&text_mutex);
cpus_read_unlock();

return 0;
}

/*
Expand Down Expand Up @@ -1362,9 +1385,15 @@ static int register_aggr_kprobe(struct kprobe *orig_p, struct kprobe *p)

if (ret == 0 && kprobe_disabled(ap) && !kprobe_disabled(p)) {
ap->flags &= ~KPROBE_FLAG_DISABLED;
if (!kprobes_all_disarmed)
if (!kprobes_all_disarmed) {
/* Arm the breakpoint again. */
arm_kprobe(ap);
ret = arm_kprobe(ap);
if (ret) {
ap->flags |= KPROBE_FLAG_DISABLED;
list_del_rcu(&p->list);
synchronize_sched();
}
}
}
return ret;
}
Expand Down Expand Up @@ -1573,8 +1602,14 @@ int register_kprobe(struct kprobe *p)
hlist_add_head_rcu(&p->hlist,
&kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]);

if (!kprobes_all_disarmed && !kprobe_disabled(p))
arm_kprobe(p);
if (!kprobes_all_disarmed && !kprobe_disabled(p)) {
ret = arm_kprobe(p);
if (ret) {
hlist_del_rcu(&p->hlist);
synchronize_sched();
goto out;
}
}

/* Try to optimize kprobe */
try_to_optimize_kprobe(p);
Expand Down Expand Up @@ -1608,11 +1643,12 @@ static int aggr_kprobe_disabled(struct kprobe *ap)
static struct kprobe *__disable_kprobe(struct kprobe *p)
{
struct kprobe *orig_p;
int ret;

/* Get an original kprobe for return */
orig_p = __get_valid_kprobe(p);
if (unlikely(orig_p == NULL))
return NULL;
return ERR_PTR(-EINVAL);

if (!kprobe_disabled(p)) {
/* Disable probe if it is a child probe */
Expand All @@ -1626,8 +1662,13 @@ static struct kprobe *__disable_kprobe(struct kprobe *p)
* should have already been disarmed, so
* skip unneed disarming process.
*/
if (!kprobes_all_disarmed)
disarm_kprobe(orig_p, true);
if (!kprobes_all_disarmed) {
ret = disarm_kprobe(orig_p, true);
if (ret) {
p->flags &= ~KPROBE_FLAG_DISABLED;
return ERR_PTR(ret);
}
}
orig_p->flags |= KPROBE_FLAG_DISABLED;
}
}
Expand All @@ -1644,8 +1685,8 @@ static int __unregister_kprobe_top(struct kprobe *p)

/* Disable kprobe. This will disarm it if needed. */
ap = __disable_kprobe(p);
if (ap == NULL)
return -EINVAL;
if (IS_ERR(ap))
return PTR_ERR(ap);

if (ap == p)
/*
Expand Down Expand Up @@ -2078,12 +2119,14 @@ static void kill_kprobe(struct kprobe *p)
int disable_kprobe(struct kprobe *kp)
{
int ret = 0;
struct kprobe *p;

mutex_lock(&kprobe_mutex);

/* Disable this kprobe */
if (__disable_kprobe(kp) == NULL)
ret = -EINVAL;
p = __disable_kprobe(kp);
if (IS_ERR(p))
ret = PTR_ERR(p);

mutex_unlock(&kprobe_mutex);
return ret;
Expand Down Expand Up @@ -2116,7 +2159,9 @@ int enable_kprobe(struct kprobe *kp)

if (!kprobes_all_disarmed && kprobe_disabled(p)) {
p->flags &= ~KPROBE_FLAG_DISABLED;
arm_kprobe(p);
ret = arm_kprobe(p);
if (ret)
p->flags |= KPROBE_FLAG_DISABLED;
}
out:
mutex_unlock(&kprobe_mutex);
Expand Down Expand Up @@ -2407,11 +2452,12 @@ static const struct file_operations debugfs_kprobe_blacklist_ops = {
.release = seq_release,
};

static void arm_all_kprobes(void)
static int arm_all_kprobes(void)
{
struct hlist_head *head;
struct kprobe *p;
unsigned int i;
unsigned int i, total = 0, errors = 0;
int err, ret = 0;

mutex_lock(&kprobe_mutex);

Expand All @@ -2428,46 +2474,74 @@ static void arm_all_kprobes(void)
/* Arming kprobes doesn't optimize kprobe itself */
for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
head = &kprobe_table[i];
hlist_for_each_entry_rcu(p, head, hlist)
if (!kprobe_disabled(p))
arm_kprobe(p);
/* Arm all kprobes on a best-effort basis */
hlist_for_each_entry_rcu(p, head, hlist) {
if (!kprobe_disabled(p)) {
err = arm_kprobe(p);
if (err) {
errors++;
ret = err;
}
total++;
}
}
}

printk(KERN_INFO "Kprobes globally enabled\n");
if (errors)
pr_warn("Kprobes globally enabled, but failed to arm %d out of %d probes\n",
errors, total);
else
pr_info("Kprobes globally enabled\n");

already_enabled:
mutex_unlock(&kprobe_mutex);
return;
return ret;
}

static void disarm_all_kprobes(void)
static int disarm_all_kprobes(void)
{
struct hlist_head *head;
struct kprobe *p;
unsigned int i;
unsigned int i, total = 0, errors = 0;
int err, ret = 0;

mutex_lock(&kprobe_mutex);

/* If kprobes are already disarmed, just return */
if (kprobes_all_disarmed) {
mutex_unlock(&kprobe_mutex);
return;
return 0;
}

kprobes_all_disarmed = true;
printk(KERN_INFO "Kprobes globally disabled\n");

for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
head = &kprobe_table[i];
/* Disarm all kprobes on a best-effort basis */
hlist_for_each_entry_rcu(p, head, hlist) {
if (!arch_trampoline_kprobe(p) && !kprobe_disabled(p))
disarm_kprobe(p, false);
if (!arch_trampoline_kprobe(p) && !kprobe_disabled(p)) {
err = disarm_kprobe(p, false);
if (err) {
errors++;
ret = err;
}
total++;
}
}
}

if (errors)
pr_warn("Kprobes globally disabled, but failed to disarm %d out of %d probes\n",
errors, total);
else
pr_info("Kprobes globally disabled\n");

mutex_unlock(&kprobe_mutex);

/* Wait for disarming all kprobes by optimizer */
wait_for_kprobe_optimizer();

return ret;
}

/*
Expand All @@ -2494,6 +2568,7 @@ static ssize_t write_enabled_file_bool(struct file *file,
{
char buf[32];
size_t buf_size;
int ret = 0;

buf_size = min(count, (sizeof(buf)-1));
if (copy_from_user(buf, user_buf, buf_size))
Expand All @@ -2504,17 +2579,20 @@ static ssize_t write_enabled_file_bool(struct file *file,
case 'y':
case 'Y':
case '1':
arm_all_kprobes();
ret = arm_all_kprobes();
break;
case 'n':
case 'N':
case '0':
disarm_all_kprobes();
ret = disarm_all_kprobes();
break;
default:
return -EINVAL;
}

if (ret)
return ret;

return count;
}

Expand Down
2 changes: 2 additions & 0 deletions tools/arch/powerpc/include/uapi/asm/kvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,8 @@ struct kvm_ppc_cpu_char {
#define KVM_REG_PPC_TIDR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xbc)
#define KVM_REG_PPC_PSSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xbd)

#define KVM_REG_PPC_DEC_EXPIRY (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xbe)

/* Transactional Memory checkpointed state:
* This is all GPRs, all VSX regs and a subset of SPRs
*/
Expand Down
Loading

0 comments on commit 9ca2c16

Please sign in to comment.