Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

tracing/fprobe: Unregister fprobe even if memory allocation fails

unregister_fprobe() can fail under memory pressure because of memory
allocation failure, but this maybe called from module unloading, and
usually there is no way to retry it. Moreover. trace_fprobe does not
check the return value.

To fix this problem, unregister fprobe and fprobe_hash_node even if
working memory allocation fails.
Anyway, if the last fprobe is removed, the filter will be freed.

Link: https://lore.kernel.org/all/177669365629.132053.8433032896213721288.stgit@mhiramat.tok.corp.google.com/

Fixes: 4346ba160409 ("fprobe: Rewrite fprobe on function-graph tracer")
Cc: stable@vger.kernel.org
Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>

+15 -10
+15 -10
kernel/trace/fprobe.c
··· 324 324 lockdep_assert_held(&fprobe_mutex); 325 325 326 326 fprobe_ftrace_active--; 327 - if (!fprobe_ftrace_active) 327 + if (!fprobe_ftrace_active) { 328 328 unregister_ftrace_function(&fprobe_ftrace_ops); 329 - if (num) 329 + ftrace_free_filter(&fprobe_ftrace_ops); 330 + } else if (num) 330 331 ftrace_set_filter_ips(&fprobe_ftrace_ops, addrs, num, 1, 0); 331 332 } 332 333 ··· 526 525 527 526 fprobe_graph_active--; 528 527 /* Q: should we unregister it ? */ 529 - if (!fprobe_graph_active) 528 + if (!fprobe_graph_active) { 530 529 unregister_ftrace_graph(&fprobe_graph_ops); 531 - 532 - if (num) 530 + ftrace_free_filter(&fprobe_graph_ops.ops); 531 + } else if (num) 533 532 ftrace_set_filter_ips(&fprobe_graph_ops.ops, addrs, num, 1, 0); 534 533 } 535 534 ··· 933 932 934 933 hlist_array = fp->hlist_array; 935 934 addrs = kcalloc(hlist_array->size, sizeof(unsigned long), GFP_KERNEL); 936 - if (!addrs) { 937 - ret = -ENOMEM; /* TODO: Fallback to one-by-one loop */ 938 - goto out; 939 - } 935 + /* 936 + * This will remove fprobe_hash_node from the hash table even if 937 + * memory allocation fails. However, ftrace_ops will not be updated. 938 + * Anyway, when the last fprobe is unregistered, ftrace_ops is also 939 + * unregistered. 940 + */ 941 + if (!addrs) 942 + pr_warn("Failed to allocate working array. ftrace_ops may not sync.\n"); 940 943 941 944 /* Remove non-synonim ips from table and hash */ 942 945 count = 0; 943 946 for (i = 0; i < hlist_array->size; i++) { 944 - if (!delete_fprobe_node(&hlist_array->array[i])) 947 + if (!delete_fprobe_node(&hlist_array->array[i]) && addrs) 945 948 addrs[count++] = hlist_array->array[i].addr; 946 949 } 947 950 del_fprobe_hash(fp);