Commit 8b6ddd10 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull tracing fixes from Steven Rostedt:

 - Have recordmcount work with > 64K sections (to support LTO)

 - kprobe RCU fixes

 - Correct a kprobe critical section with missing mutex

 - Remove redundant arch_disarm_kprobe() call

 - Fix lockup when kretprobe triggers within kprobe_flush_task()

 - Fix memory leak in fetch_op_data operations

 - Fix sleep in atomic in ftrace trace array sample code

 - Free up memory on failure in sample trace array code

 - Fix incorrect reporting of function_graph fields in format file

 - Fix quote within quote parsing in bootconfig

 - Fix return value of bootconfig tool

 - Add testcases for bootconfig tool

 - Fix maybe uninitialized warning in ftrace pid file code

 - Remove unused variable in tracing_iter_reset()

 - Fix some typos

* tag 'trace-v5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace:
  ftrace: Fix maybe-uninitialized compiler warning
  tools/bootconfig: Add testcase for show-command and quotes test
  tools/bootconfig: Fix to return 0 if succeeded to show the bootconfig
  tools/bootconfig: Fix to use correct quotes for value
  proc/bootconfig: Fix to use correct quotes for value
  tracing: Remove unused event variable in tracing_iter_reset
  tracing/probe: Fix memleak in fetch_op_data operations
  trace: Fix typo in allocate_ftrace_ops()'s comment
  tracing: Make ftrace packed events have align of 1
  sample-trace-array: Remove trace_array 'sample-instance'
  sample-trace-array: Fix sleeping function called from invalid context
  kretprobe: Prevent triggering kretprobe from within kprobe_flush_task
  kprobes: Remove redundant arch_disarm_kprobe() call
  kprobes: Fix to protect kick_kprobe_optimizer() by kprobe_mutex
  kprobes: Use non RCU traversal APIs on kprobe_tables if possible
  kprobes: Suppress the suspicious RCU warning on kprobes
  recordmcount: support >64k sections
parents eede2b9b 026bb845
Loading
Loading
Loading
Loading
+3 −13
Original line number Diff line number Diff line
@@ -754,16 +754,11 @@ asm(
NOKPROBE_SYMBOL(kretprobe_trampoline);
STACK_FRAME_NON_STANDARD(kretprobe_trampoline);

static struct kprobe kretprobe_kprobe = {
	.addr = (void *)kretprobe_trampoline,
};

/*
 * Called from kretprobe_trampoline
 */
__used __visible void *trampoline_handler(struct pt_regs *regs)
{
	struct kprobe_ctlblk *kcb;
	struct kretprobe_instance *ri = NULL;
	struct hlist_head *head, empty_rp;
	struct hlist_node *tmp;
@@ -773,16 +768,12 @@ __used __visible void *trampoline_handler(struct pt_regs *regs)
	void *frame_pointer;
	bool skipped = false;

	preempt_disable();

	/*
	 * Set a dummy kprobe for avoiding kretprobe recursion.
	 * Since kretprobe never run in kprobe handler, kprobe must not
	 * be running at this point.
	 */
	kcb = get_kprobe_ctlblk();
	__this_cpu_write(current_kprobe, &kretprobe_kprobe);
	kcb->kprobe_status = KPROBE_HIT_ACTIVE;
	kprobe_busy_begin();

	INIT_HLIST_HEAD(&empty_rp);
	kretprobe_hash_lock(current, &head, &flags);
@@ -858,7 +849,7 @@ __used __visible void *trampoline_handler(struct pt_regs *regs)
			__this_cpu_write(current_kprobe, &ri->rp->kp);
			ri->ret_addr = correct_ret_addr;
			ri->rp->handler(ri, regs);
			__this_cpu_write(current_kprobe, &kretprobe_kprobe);
			__this_cpu_write(current_kprobe, &kprobe_busy);
		}

		recycle_rp_inst(ri, &empty_rp);
@@ -874,8 +865,7 @@ __used __visible void *trampoline_handler(struct pt_regs *regs)

	kretprobe_hash_unlock(current, &flags);

	__this_cpu_write(current_kprobe, NULL);
	preempt_enable();
	kprobe_busy_end();

	hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
		hlist_del(&ri->hlist);
+10 −5
Original line number Diff line number Diff line
@@ -26,8 +26,9 @@ static int boot_config_proc_show(struct seq_file *m, void *v)
static int __init copy_xbc_key_value_list(char *dst, size_t size)
{
	struct xbc_node *leaf, *vnode;
	const char *val;
	char *key, *end = dst + size;
	const char *val;
	char q;
	int ret = 0;

	key = kzalloc(XBC_KEYLEN_MAX, GFP_KERNEL);
@@ -41,16 +42,20 @@ static int __init copy_xbc_key_value_list(char *dst, size_t size)
			break;
		dst += ret;
		vnode = xbc_node_get_child(leaf);
		if (vnode && xbc_node_is_array(vnode)) {
		if (vnode) {
			xbc_array_for_each_value(vnode, val) {
				ret = snprintf(dst, rest(dst, end), "\"%s\"%s",
					val, vnode->next ? ", " : "\n");
				if (strchr(val, '"'))
					q = '\'';
				else
					q = '"';
				ret = snprintf(dst, rest(dst, end), "%c%s%c%s",
					q, val, q, vnode->next ? ", " : "\n");
				if (ret < 0)
					goto out;
				dst += ret;
			}
		} else {
			ret = snprintf(dst, rest(dst, end), "\"%s\"\n", val);
			ret = snprintf(dst, rest(dst, end), "\"\"\n");
			if (ret < 0)
				break;
			dst += ret;
+4 −0
Original line number Diff line number Diff line
@@ -350,6 +350,10 @@ static inline struct kprobe_ctlblk *get_kprobe_ctlblk(void)
	return this_cpu_ptr(&kprobe_ctlblk);
}

extern struct kprobe kprobe_busy;
void kprobe_busy_begin(void);
void kprobe_busy_end(void);

kprobe_opcode_t *kprobe_lookup_name(const char *name, unsigned int offset);
int register_kprobe(struct kprobe *p);
void unregister_kprobe(struct kprobe *p);
+48 −13
Original line number Diff line number Diff line
@@ -46,6 +46,11 @@


static int kprobes_initialized;
/* kprobe_table can be accessed by
 * - Normal hlist traversal and RCU add/del under kprobe_mutex is held.
 * Or
 * - RCU hlist traversal under disabling preempt (breakpoint handlers)
 */
static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE];
static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE];

@@ -326,7 +331,8 @@ struct kprobe *get_kprobe(void *addr)
	struct kprobe *p;

	head = &kprobe_table[hash_ptr(addr, KPROBE_HASH_BITS)];
	hlist_for_each_entry_rcu(p, head, hlist) {
	hlist_for_each_entry_rcu(p, head, hlist,
				 lockdep_is_held(&kprobe_mutex)) {
		if (p->addr == addr)
			return p;
	}
@@ -586,11 +592,12 @@ static void kprobe_optimizer(struct work_struct *work)
	mutex_unlock(&module_mutex);
	mutex_unlock(&text_mutex);
	cpus_read_unlock();
	mutex_unlock(&kprobe_mutex);

	/* Step 5: Kick optimizer again if needed */
	if (!list_empty(&optimizing_list) || !list_empty(&unoptimizing_list))
		kick_kprobe_optimizer();

	mutex_unlock(&kprobe_mutex);
}

/* Wait for completing optimization and unoptimization */
@@ -668,8 +675,6 @@ static void force_unoptimize_kprobe(struct optimized_kprobe *op)
	lockdep_assert_cpus_held();
	arch_unoptimize_kprobe(op);
	op->kp.flags &= ~KPROBE_FLAG_OPTIMIZED;
	if (kprobe_disabled(&op->kp))
		arch_disarm_kprobe(&op->kp);
}

/* Unoptimize a kprobe if p is optimized */
@@ -849,7 +854,7 @@ static void optimize_all_kprobes(void)
	kprobes_allow_optimization = true;
	for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
		head = &kprobe_table[i];
		hlist_for_each_entry_rcu(p, head, hlist)
		hlist_for_each_entry(p, head, hlist)
			if (!kprobe_disabled(p))
				optimize_kprobe(p);
	}
@@ -876,7 +881,7 @@ static void unoptimize_all_kprobes(void)
	kprobes_allow_optimization = false;
	for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
		head = &kprobe_table[i];
		hlist_for_each_entry_rcu(p, head, hlist) {
		hlist_for_each_entry(p, head, hlist) {
			if (!kprobe_disabled(p))
				unoptimize_kprobe(p, false);
		}
@@ -1236,6 +1241,26 @@ __releases(hlist_lock)
}
NOKPROBE_SYMBOL(kretprobe_table_unlock);

struct kprobe kprobe_busy = {
	.addr = (void *) get_kprobe,
};

void kprobe_busy_begin(void)
{
	struct kprobe_ctlblk *kcb;

	preempt_disable();
	__this_cpu_write(current_kprobe, &kprobe_busy);
	kcb = get_kprobe_ctlblk();
	kcb->kprobe_status = KPROBE_HIT_ACTIVE;
}

void kprobe_busy_end(void)
{
	__this_cpu_write(current_kprobe, NULL);
	preempt_enable();
}

/*
 * This function is called from finish_task_switch when task tk becomes dead,
 * so that we can recycle any function-return probe instances associated
@@ -1253,6 +1278,8 @@ void kprobe_flush_task(struct task_struct *tk)
		/* Early boot.  kretprobe_table_locks not yet initialized. */
		return;

	kprobe_busy_begin();

	INIT_HLIST_HEAD(&empty_rp);
	hash = hash_ptr(tk, KPROBE_HASH_BITS);
	head = &kretprobe_inst_table[hash];
@@ -1266,6 +1293,8 @@ void kprobe_flush_task(struct task_struct *tk)
		hlist_del(&ri->hlist);
		kfree(ri);
	}

	kprobe_busy_end();
}
NOKPROBE_SYMBOL(kprobe_flush_task);

@@ -1499,12 +1528,14 @@ static struct kprobe *__get_valid_kprobe(struct kprobe *p)
{
	struct kprobe *ap, *list_p;

	lockdep_assert_held(&kprobe_mutex);

	ap = get_kprobe(p->addr);
	if (unlikely(!ap))
		return NULL;

	if (p != ap) {
		list_for_each_entry_rcu(list_p, &ap->list, list)
		list_for_each_entry(list_p, &ap->list, list)
			if (list_p == p)
			/* kprobe p is a valid probe */
				goto valid;
@@ -1669,7 +1700,9 @@ static int aggr_kprobe_disabled(struct kprobe *ap)
{
	struct kprobe *kp;

	list_for_each_entry_rcu(kp, &ap->list, list)
	lockdep_assert_held(&kprobe_mutex);

	list_for_each_entry(kp, &ap->list, list)
		if (!kprobe_disabled(kp))
			/*
			 * There is an active probe on the list.
@@ -1748,7 +1781,7 @@ static int __unregister_kprobe_top(struct kprobe *p)
	else {
		/* If disabling probe has special handlers, update aggrprobe */
		if (p->post_handler && !kprobe_gone(p)) {
			list_for_each_entry_rcu(list_p, &ap->list, list) {
			list_for_each_entry(list_p, &ap->list, list) {
				if ((list_p != p) && (list_p->post_handler))
					goto noclean;
			}
@@ -2062,13 +2095,15 @@ static void kill_kprobe(struct kprobe *p)
{
	struct kprobe *kp;

	lockdep_assert_held(&kprobe_mutex);

	p->flags |= KPROBE_FLAG_GONE;
	if (kprobe_aggrprobe(p)) {
		/*
		 * If this is an aggr_kprobe, we have to list all the
		 * chained probes and mark them GONE.
		 */
		list_for_each_entry_rcu(kp, &p->list, list)
		list_for_each_entry(kp, &p->list, list)
			kp->flags |= KPROBE_FLAG_GONE;
		p->post_handler = NULL;
		kill_optimized_kprobe(p);
@@ -2312,7 +2347,7 @@ static int kprobes_module_callback(struct notifier_block *nb,
	mutex_lock(&kprobe_mutex);
	for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
		head = &kprobe_table[i];
		hlist_for_each_entry_rcu(p, head, hlist)
		hlist_for_each_entry(p, head, hlist)
			if (within_module_init((unsigned long)p->addr, mod) ||
			    (checkcore &&
			     within_module_core((unsigned long)p->addr, mod))) {
@@ -2550,7 +2585,7 @@ static int arm_all_kprobes(void)
	for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
		head = &kprobe_table[i];
		/* Arm all kprobes on a best-effort basis */
		hlist_for_each_entry_rcu(p, head, hlist) {
		hlist_for_each_entry(p, head, hlist) {
			if (!kprobe_disabled(p)) {
				err = arm_kprobe(p);
				if (err)  {
@@ -2593,7 +2628,7 @@ static int disarm_all_kprobes(void)
	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) {
		hlist_for_each_entry(p, head, hlist) {
			if (!arch_trampoline_kprobe(p) && !kprobe_disabled(p)) {
				err = disarm_kprobe(p, false);
				if (err) {
+10 −2
Original line number Diff line number Diff line
@@ -7151,6 +7151,10 @@ static int pid_open(struct inode *inode, struct file *file, int type)
	case TRACE_NO_PIDS:
		seq_ops = &ftrace_no_pid_sops;
		break;
	default:
		trace_array_put(tr);
		WARN_ON_ONCE(1);
		return -EINVAL;
	}

	ret = seq_open(file, seq_ops);
@@ -7229,6 +7233,10 @@ pid_write(struct file *filp, const char __user *ubuf,
		other_pids = rcu_dereference_protected(tr->function_pids,
					     lockdep_is_held(&ftrace_lock));
		break;
	default:
		ret = -EINVAL;
		WARN_ON_ONCE(1);
		goto out;
	}

	ret = trace_pid_write(filtered_pids, &pid_list, ubuf, cnt);
Loading