Skip to content

Commit a35fb2b

Browse files
committed
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>
1 parent 54c7939 commit a35fb2b

File tree

1 file changed

+36
-30
lines changed

1 file changed

+36
-30
lines changed

kernel/kprobes.c

Lines changed: 36 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -144,30 +144,26 @@ kprobe_opcode_t *__get_insn_slot(struct kprobe_insn_cache *c)
144144

145145
/* Since the slot array is not protected by rcu, we need a mutex */
146146
guard(mutex)(&c->mutex);
147-
retry:
148-
rcu_read_lock();
149-
list_for_each_entry_rcu(kip, &c->pages, list) {
150-
if (kip->nused < slots_per_page(c)) {
151-
int i;
152-
153-
for (i = 0; i < slots_per_page(c); i++) {
154-
if (kip->slot_used[i] == SLOT_CLEAN) {
155-
kip->slot_used[i] = SLOT_USED;
156-
kip->nused++;
157-
rcu_read_unlock();
158-
return kip->insns + (i * c->insn_size);
147+
do {
148+
guard(rcu)();
149+
list_for_each_entry_rcu(kip, &c->pages, list) {
150+
if (kip->nused < slots_per_page(c)) {
151+
int i;
152+
153+
for (i = 0; i < slots_per_page(c); i++) {
154+
if (kip->slot_used[i] == SLOT_CLEAN) {
155+
kip->slot_used[i] = SLOT_USED;
156+
kip->nused++;
157+
return kip->insns + (i * c->insn_size);
158+
}
159159
}
160+
/* kip->nused is broken. Fix it. */
161+
kip->nused = slots_per_page(c);
162+
WARN_ON(1);
160163
}
161-
/* kip->nused is broken. Fix it. */
162-
kip->nused = slots_per_page(c);
163-
WARN_ON(1);
164164
}
165-
}
166-
rcu_read_unlock();
167-
168165
/* If there are any garbage slots, collect it and try again. */
169-
if (c->nr_garbage && collect_garbage_slots(c) == 0)
170-
goto retry;
166+
} while (c->nr_garbage && collect_garbage_slots(c) == 0);
171167

172168
/* All out of space. Need to allocate a new page. */
173169
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)
246242
return 0;
247243
}
248244

249-
void __free_insn_slot(struct kprobe_insn_cache *c,
250-
kprobe_opcode_t *slot, int dirty)
245+
static long __find_insn_page(struct kprobe_insn_cache *c,
246+
kprobe_opcode_t *slot, struct kprobe_insn_page **pkip)
251247
{
252-
struct kprobe_insn_page *kip;
248+
struct kprobe_insn_page *kip = NULL;
253249
long idx;
254250

255-
guard(mutex)(&c->mutex);
256-
rcu_read_lock();
251+
guard(rcu)();
257252
list_for_each_entry_rcu(kip, &c->pages, list) {
258253
idx = ((long)slot - (long)kip->insns) /
259254
(c->insn_size * sizeof(kprobe_opcode_t));
260-
if (idx >= 0 && idx < slots_per_page(c))
261-
goto out;
255+
if (idx >= 0 && idx < slots_per_page(c)) {
256+
*pkip = kip;
257+
return idx;
258+
}
262259
}
263260
/* Could not find this slot. */
264261
WARN_ON(1);
265-
kip = NULL;
266-
out:
267-
rcu_read_unlock();
262+
*pkip = NULL;
263+
return -1;
264+
}
265+
266+
void __free_insn_slot(struct kprobe_insn_cache *c,
267+
kprobe_opcode_t *slot, int dirty)
268+
{
269+
struct kprobe_insn_page *kip = NULL;
270+
long idx;
271+
272+
guard(mutex)(&c->mutex);
273+
idx = __find_insn_page(c, slot, &kip);
268274
/* Mark and sweep: this may sleep */
269275
if (kip) {
270276
/* Check double free */

0 commit comments

Comments
 (0)