Skip to content

Commit 9345ec2

Browse files
mhiramatgregkh
authored andcommitted
tracing/fprobe: Avoid kcalloc() in rcu_read_lock section
commit aa72812 upstream. fprobe_remove_node_in_module() is called under RCU read locked, but this invokes kcalloc() if there are more than 8 fprobes installed on the module. Sashiko warns it because kcalloc() can sleep [1]. [1] https://sashiko.dev/#/patchset/177552432201.853249.5125045538812833325.stgit%40mhiramat.tok.corp.google.com To fix this issue, expand the batch size to 128 and do not expand the fprobe_addr_list, but just cancel walking on fprobe_ip_table, update fgraph/ftrace_ops and retry the loop again. Link: https://lore.kernel.org/all/177669367206.132053.1493637946869032744.stgit@mhiramat.tok.corp.google.com/ Fixes: 0de4c70 ("tracing: fprobe: use rhltable for fprobe_ip_table") Cc: stable@vger.kernel.org Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 0e8e57f commit 9345ec2

1 file changed

Lines changed: 45 additions & 47 deletions

File tree

kernel/trace/fprobe.c

Lines changed: 45 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -336,11 +336,10 @@ static bool fprobe_is_ftrace(struct fprobe *fp)
336336
}
337337

338338
#ifdef CONFIG_MODULES
339-
static void fprobe_set_ips(unsigned long *ips, unsigned int cnt, int remove,
340-
int reset)
339+
static void fprobe_remove_ips(unsigned long *ips, unsigned int cnt)
341340
{
342-
ftrace_set_filter_ips(&fprobe_graph_ops.ops, ips, cnt, remove, reset);
343-
ftrace_set_filter_ips(&fprobe_ftrace_ops, ips, cnt, remove, reset);
341+
ftrace_set_filter_ips(&fprobe_graph_ops.ops, ips, cnt, 1, 0);
342+
ftrace_set_filter_ips(&fprobe_ftrace_ops, ips, cnt, 1, 0);
344343
}
345344
#endif
346345
#else
@@ -359,10 +358,9 @@ static bool fprobe_is_ftrace(struct fprobe *fp)
359358
}
360359

361360
#ifdef CONFIG_MODULES
362-
static void fprobe_set_ips(unsigned long *ips, unsigned int cnt, int remove,
363-
int reset)
361+
static void fprobe_remove_ips(unsigned long *ips, unsigned int cnt)
364362
{
365-
ftrace_set_filter_ips(&fprobe_graph_ops.ops, ips, cnt, remove, reset);
363+
ftrace_set_filter_ips(&fprobe_graph_ops.ops, ips, cnt, 1, 0);
366364
}
367365
#endif
368366
#endif /* !CONFIG_DYNAMIC_FTRACE_WITH_ARGS && !CONFIG_DYNAMIC_FTRACE_WITH_REGS */
@@ -536,53 +534,32 @@ static void fprobe_graph_remove_ips(unsigned long *addrs, int num)
536534

537535
#ifdef CONFIG_MODULES
538536

539-
#define FPROBE_IPS_BATCH_INIT 8
537+
#define FPROBE_IPS_BATCH_INIT 128
540538
/* instruction pointer address list */
541539
struct fprobe_addr_list {
542540
int index;
543541
int size;
544542
unsigned long *addrs;
545543
};
546544

547-
static int fprobe_addr_list_add(struct fprobe_addr_list *alist, unsigned long addr)
545+
static int fprobe_remove_node_in_module(struct module *mod, struct fprobe_hlist_node *node,
546+
struct fprobe_addr_list *alist)
548547
{
549-
unsigned long *addrs;
550-
551-
/* Previously we failed to expand the list. */
552-
if (alist->index == alist->size)
553-
return -ENOSPC;
554-
555-
alist->addrs[alist->index++] = addr;
556-
if (alist->index < alist->size)
548+
if (!within_module(node->addr, mod))
557549
return 0;
558550

559-
/* Expand the address list */
560-
addrs = kcalloc(alist->size * 2, sizeof(*addrs), GFP_KERNEL);
561-
if (!addrs)
562-
return -ENOMEM;
563-
564-
memcpy(addrs, alist->addrs, alist->size * sizeof(*addrs));
565-
alist->size *= 2;
566-
kfree(alist->addrs);
567-
alist->addrs = addrs;
551+
if (delete_fprobe_node(node))
552+
return 0;
553+
/* If no address list is available, we can't track this address. */
554+
if (!alist->addrs)
555+
return 0;
568556

557+
alist->addrs[alist->index++] = node->addr;
558+
if (alist->index == alist->size)
559+
return -ENOSPC;
569560
return 0;
570561
}
571562

572-
static void fprobe_remove_node_in_module(struct module *mod, struct fprobe_hlist_node *node,
573-
struct fprobe_addr_list *alist)
574-
{
575-
if (!within_module(node->addr, mod))
576-
return;
577-
if (delete_fprobe_node(node))
578-
return;
579-
/*
580-
* If failed to update alist, just continue to update hlist.
581-
* Therefore, at list user handler will not hit anymore.
582-
*/
583-
fprobe_addr_list_add(alist, node->addr);
584-
}
585-
586563
/* Handle module unloading to manage fprobe_ip_table. */
587564
static int fprobe_module_callback(struct notifier_block *nb,
588565
unsigned long val, void *data)
@@ -591,29 +568,50 @@ static int fprobe_module_callback(struct notifier_block *nb,
591568
struct fprobe_hlist_node *node;
592569
struct rhashtable_iter iter;
593570
struct module *mod = data;
571+
bool retry;
594572

595573
if (val != MODULE_STATE_GOING)
596574
return NOTIFY_DONE;
597575

598576
alist.addrs = kcalloc(alist.size, sizeof(*alist.addrs), GFP_KERNEL);
599-
/* If failed to alloc memory, we can not remove ips from hash. */
600-
if (!alist.addrs)
601-
return NOTIFY_DONE;
577+
/*
578+
* If failed to alloc memory, ftrace_ops will not be able to remove ips from
579+
* hash, but we can still remove nodes from fprobe_ip_table, so we can avoid
580+
* the potential wrong callback. So just print a warning here and try to
581+
* continue without address list.
582+
*/
583+
WARN_ONCE(!alist.addrs,
584+
"Failed to allocate memory for fprobe_addr_list, ftrace_ops will not be updated");
602585

603586
mutex_lock(&fprobe_mutex);
587+
again:
588+
retry = false;
589+
alist.index = 0;
604590
rhltable_walk_enter(&fprobe_ip_table, &iter);
605591
do {
606592
rhashtable_walk_start(&iter);
607593

608594
while ((node = rhashtable_walk_next(&iter)) && !IS_ERR(node))
609-
fprobe_remove_node_in_module(mod, node, &alist);
595+
if (fprobe_remove_node_in_module(mod, node, &alist) < 0) {
596+
retry = true;
597+
break;
598+
}
610599

611600
rhashtable_walk_stop(&iter);
612-
} while (node == ERR_PTR(-EAGAIN));
601+
} while (node == ERR_PTR(-EAGAIN) && !retry);
613602
rhashtable_walk_exit(&iter);
603+
/* Remove any ips from hash table(s) */
604+
if (alist.index > 0) {
605+
fprobe_remove_ips(alist.addrs, alist.index);
606+
/*
607+
* If we break rhashtable walk loop except for -EAGAIN, we need
608+
* to restart looping from start for safety. Anyway, this is
609+
* not a hotpath.
610+
*/
611+
if (retry)
612+
goto again;
613+
}
614614

615-
if (alist.index > 0)
616-
fprobe_set_ips(alist.addrs, alist.index, 1, 0);
617615
mutex_unlock(&fprobe_mutex);
618616

619617
kfree(alist.addrs);

0 commit comments

Comments
 (0)