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: Masami Hiramatsu (Google) <mhiramat@kernel.org>
This commit is contained in:
Masami Hiramatsu (Google) 2024-12-09 11:41:38 +09:00
parent 54c7939011
commit a35fb2bcae

View File

@ -144,30 +144,26 @@ 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();
list_for_each_entry_rcu(kip, &c->pages, list) {
if (kip->nused < slots_per_page(c)) {
int i;
do {
guard(rcu)();
list_for_each_entry_rcu(kip, &c->pages, list) {
if (kip->nused < slots_per_page(c)) {
int i;
for (i = 0; i < slots_per_page(c); i++) {
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);
for (i = 0; i < slots_per_page(c); i++) {
if (kip->slot_used[i] == SLOT_CLEAN) {
kip->slot_used[i] = SLOT_USED;
kip->nused++;
return kip->insns + (i * c->insn_size);
}
}
/* kip->nused is broken. Fix it. */
kip->nused = slots_per_page(c);
WARN_ON(1);
}
/* kip->nused is broken. Fix it. */
kip->nused = slots_per_page(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 */