Commit a35fb2bc authored by Masami Hiramatsu (Google)'s avatar Masami Hiramatsu (Google)
Browse files

kprobes: Use guard for rcu_read_lock

Use guard(rcu) for rcu_read_lock so that it can remove unneeded
gotos and make it more structured.

Link: https://lore.kernel.org/all/173371209846.480397.3852648910271029695.stgit@devnote2/



Signed-off-by: default avatarMasami Hiramatsu (Google) <mhiramat@kernel.org>
parent 54c79390
Loading
Loading
Loading
Loading
+36 −30
Original line number Diff line number Diff line
@@ -144,8 +144,8 @@ kprobe_opcode_t *__get_insn_slot(struct kprobe_insn_cache *c)

	/* Since the slot array is not protected by rcu, we need a mutex */
	guard(mutex)(&c->mutex);
 retry:
	rcu_read_lock();
	do {
		guard(rcu)();
		list_for_each_entry_rcu(kip, &c->pages, list) {
			if (kip->nused < slots_per_page(c)) {
				int i;
@@ -154,7 +154,6 @@ kprobe_opcode_t *__get_insn_slot(struct kprobe_insn_cache *c)
					if (kip->slot_used[i] == SLOT_CLEAN) {
						kip->slot_used[i] = SLOT_USED;
						kip->nused++;
					rcu_read_unlock();
						return kip->insns + (i * c->insn_size);
					}
				}
@@ -163,11 +162,8 @@ kprobe_opcode_t *__get_insn_slot(struct kprobe_insn_cache *c)
				WARN_ON(1);
			}
		}
	rcu_read_unlock();

	/* If there are any garbage slots, collect it and try again. */
	if (c->nr_garbage && collect_garbage_slots(c) == 0)
		goto retry;
	} while (c->nr_garbage && collect_garbage_slots(c) == 0);

	/* All out of space.  Need to allocate a new page. */
	kip = kmalloc(struct_size(kip, slot_used, slots_per_page(c)), GFP_KERNEL);
@@ -246,25 +242,35 @@ static int collect_garbage_slots(struct kprobe_insn_cache *c)
	return 0;
}

void __free_insn_slot(struct kprobe_insn_cache *c,
		      kprobe_opcode_t *slot, int dirty)
static long __find_insn_page(struct kprobe_insn_cache *c,
	kprobe_opcode_t *slot, struct kprobe_insn_page **pkip)
{
	struct kprobe_insn_page *kip;
	struct kprobe_insn_page *kip = NULL;
	long idx;

	guard(mutex)(&c->mutex);
	rcu_read_lock();
	guard(rcu)();
	list_for_each_entry_rcu(kip, &c->pages, list) {
		idx = ((long)slot - (long)kip->insns) /
			(c->insn_size * sizeof(kprobe_opcode_t));
		if (idx >= 0 && idx < slots_per_page(c))
			goto out;
		if (idx >= 0 && idx < slots_per_page(c)) {
			*pkip = kip;
			return idx;
		}
	}
	/* Could not find this slot. */
	WARN_ON(1);
	kip = NULL;
out:
	rcu_read_unlock();
	*pkip = NULL;
	return -1;
}

void __free_insn_slot(struct kprobe_insn_cache *c,
		      kprobe_opcode_t *slot, int dirty)
{
	struct kprobe_insn_page *kip = NULL;
	long idx;

	guard(mutex)(&c->mutex);
	idx = __find_insn_page(c, slot, &kip);
	/* Mark and sweep: this may sleep */
	if (kip) {
		/* Check double free */