Skip to content

Commit 257dcf2

Browse files
committed
Merge tag 'trace-v5.16-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace
Pull tracing fixes from Steven Rostedt: "Tracing, ftrace and tracefs fixes: - Have tracefs honor the gid mount option - Have new files in tracefs inherit the parent ownership - Have direct_ops unregister when it has no more functions - Properly clean up the ops when unregistering multi direct ops - Add a sample module to test the multiple direct ops - Fix memory leak in error path of __create_synth_event()" * tag 'trace-v5.16-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace: tracing: Fix possible memory leak in __create_synth_event() error path ftrace/samples: Add module to test multi direct modify interface ftrace: Add cleanup to unregister_ftrace_direct_multi ftrace: Use direct_ops hash in unregister_ftrace_direct tracefs: Set all files to the same group ownership as the mount option tracefs: Have new files inherit the ownership of their parent
2 parents 0d21e66 + c24be24 commit 257dcf2

File tree

5 files changed

+242
-6
lines changed

5 files changed

+242
-6
lines changed

fs/tracefs/inode.c

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,77 @@ struct tracefs_fs_info {
161161
struct tracefs_mount_opts mount_opts;
162162
};
163163

164+
static void change_gid(struct dentry *dentry, kgid_t gid)
165+
{
166+
if (!dentry->d_inode)
167+
return;
168+
dentry->d_inode->i_gid = gid;
169+
}
170+
171+
/*
172+
* Taken from d_walk, but without he need for handling renames.
173+
* Nothing can be renamed while walking the list, as tracefs
174+
* does not support renames. This is only called when mounting
175+
* or remounting the file system, to set all the files to
176+
* the given gid.
177+
*/
178+
static void set_gid(struct dentry *parent, kgid_t gid)
179+
{
180+
struct dentry *this_parent;
181+
struct list_head *next;
182+
183+
this_parent = parent;
184+
spin_lock(&this_parent->d_lock);
185+
186+
change_gid(this_parent, gid);
187+
repeat:
188+
next = this_parent->d_subdirs.next;
189+
resume:
190+
while (next != &this_parent->d_subdirs) {
191+
struct list_head *tmp = next;
192+
struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
193+
next = tmp->next;
194+
195+
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
196+
197+
change_gid(dentry, gid);
198+
199+
if (!list_empty(&dentry->d_subdirs)) {
200+
spin_unlock(&this_parent->d_lock);
201+
spin_release(&dentry->d_lock.dep_map, _RET_IP_);
202+
this_parent = dentry;
203+
spin_acquire(&this_parent->d_lock.dep_map, 0, 1, _RET_IP_);
204+
goto repeat;
205+
}
206+
spin_unlock(&dentry->d_lock);
207+
}
208+
/*
209+
* All done at this level ... ascend and resume the search.
210+
*/
211+
rcu_read_lock();
212+
ascend:
213+
if (this_parent != parent) {
214+
struct dentry *child = this_parent;
215+
this_parent = child->d_parent;
216+
217+
spin_unlock(&child->d_lock);
218+
spin_lock(&this_parent->d_lock);
219+
220+
/* go into the first sibling still alive */
221+
do {
222+
next = child->d_child.next;
223+
if (next == &this_parent->d_subdirs)
224+
goto ascend;
225+
child = list_entry(next, struct dentry, d_child);
226+
} while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED));
227+
rcu_read_unlock();
228+
goto resume;
229+
}
230+
rcu_read_unlock();
231+
spin_unlock(&this_parent->d_lock);
232+
return;
233+
}
234+
164235
static int tracefs_parse_options(char *data, struct tracefs_mount_opts *opts)
165236
{
166237
substring_t args[MAX_OPT_ARGS];
@@ -193,6 +264,7 @@ static int tracefs_parse_options(char *data, struct tracefs_mount_opts *opts)
193264
if (!gid_valid(gid))
194265
return -EINVAL;
195266
opts->gid = gid;
267+
set_gid(tracefs_mount->mnt_root, gid);
196268
break;
197269
case Opt_mode:
198270
if (match_octal(&args[0], &option))
@@ -414,6 +486,8 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode,
414486
inode->i_mode = mode;
415487
inode->i_fop = fops ? fops : &tracefs_file_operations;
416488
inode->i_private = data;
489+
inode->i_uid = d_inode(dentry->d_parent)->i_uid;
490+
inode->i_gid = d_inode(dentry->d_parent)->i_gid;
417491
d_instantiate(dentry, inode);
418492
fsnotify_create(dentry->d_parent->d_inode, dentry);
419493
return end_creating(dentry);
@@ -436,6 +510,8 @@ static struct dentry *__create_dir(const char *name, struct dentry *parent,
436510
inode->i_mode = S_IFDIR | S_IRWXU | S_IRUSR| S_IRGRP | S_IXUSR | S_IXGRP;
437511
inode->i_op = ops;
438512
inode->i_fop = &simple_dir_operations;
513+
inode->i_uid = d_inode(dentry->d_parent)->i_uid;
514+
inode->i_gid = d_inode(dentry->d_parent)->i_gid;
439515

440516
/* directory inodes start off with i_nlink == 2 (for "." entry) */
441517
inc_nlink(inode);

kernel/trace/ftrace.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5217,6 +5217,7 @@ int unregister_ftrace_direct(unsigned long ip, unsigned long addr)
52175217
{
52185218
struct ftrace_direct_func *direct;
52195219
struct ftrace_func_entry *entry;
5220+
struct ftrace_hash *hash;
52205221
int ret = -ENODEV;
52215222

52225223
mutex_lock(&direct_mutex);
@@ -5225,7 +5226,8 @@ int unregister_ftrace_direct(unsigned long ip, unsigned long addr)
52255226
if (!entry)
52265227
goto out_unlock;
52275228

5228-
if (direct_functions->count == 1)
5229+
hash = direct_ops.func_hash->filter_hash;
5230+
if (hash->count == 1)
52295231
unregister_ftrace_function(&direct_ops);
52305232

52315233
ret = ftrace_set_filter_ip(&direct_ops, ip, 1, 0);
@@ -5540,6 +5542,10 @@ int unregister_ftrace_direct_multi(struct ftrace_ops *ops, unsigned long addr)
55405542
err = unregister_ftrace_function(ops);
55415543
remove_direct_functions_hash(hash, addr);
55425544
mutex_unlock(&direct_mutex);
5545+
5546+
/* cleanup for possible another register call */
5547+
ops->func = NULL;
5548+
ops->trampoline = 0;
55435549
return err;
55445550
}
55455551
EXPORT_SYMBOL_GPL(unregister_ftrace_direct_multi);

kernel/trace/trace_events_synth.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,9 +1237,8 @@ static int __create_synth_event(const char *name, const char *raw_fields)
12371237
argv + consumed, &consumed,
12381238
&field_version);
12391239
if (IS_ERR(field)) {
1240-
argv_free(argv);
12411240
ret = PTR_ERR(field);
1242-
goto err;
1241+
goto err_free_arg;
12431242
}
12441243

12451244
/*
@@ -1262,26 +1261,26 @@ static int __create_synth_event(const char *name, const char *raw_fields)
12621261
if (cmd_version > 1 && n_fields_this_loop >= 1) {
12631262
synth_err(SYNTH_ERR_INVALID_CMD, errpos(field_str));
12641263
ret = -EINVAL;
1265-
goto err;
1264+
goto err_free_arg;
12661265
}
12671266

12681267
fields[n_fields++] = field;
12691268
if (n_fields == SYNTH_FIELDS_MAX) {
12701269
synth_err(SYNTH_ERR_TOO_MANY_FIELDS, 0);
12711270
ret = -EINVAL;
1272-
goto err;
1271+
goto err_free_arg;
12731272
}
12741273

12751274
n_fields_this_loop++;
12761275
}
1276+
argv_free(argv);
12771277

12781278
if (consumed < argc) {
12791279
synth_err(SYNTH_ERR_INVALID_CMD, 0);
12801280
ret = -EINVAL;
12811281
goto err;
12821282
}
12831283

1284-
argv_free(argv);
12851284
}
12861285

12871286
if (n_fields == 0) {
@@ -1307,6 +1306,8 @@ static int __create_synth_event(const char *name, const char *raw_fields)
13071306
kfree(saved_fields);
13081307

13091308
return ret;
1309+
err_free_arg:
1310+
argv_free(argv);
13101311
err:
13111312
for (i = 0; i < n_fields; i++)
13121313
free_synth_field(fields[i]);

samples/ftrace/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ obj-$(CONFIG_SAMPLE_FTRACE_DIRECT) += ftrace-direct.o
44
obj-$(CONFIG_SAMPLE_FTRACE_DIRECT) += ftrace-direct-too.o
55
obj-$(CONFIG_SAMPLE_FTRACE_DIRECT) += ftrace-direct-modify.o
66
obj-$(CONFIG_SAMPLE_FTRACE_DIRECT_MULTI) += ftrace-direct-multi.o
7+
obj-$(CONFIG_SAMPLE_FTRACE_DIRECT_MULTI) += ftrace-direct-multi-modify.o
78

89
CFLAGS_sample-trace-array.o := -I$(src)
910
obj-$(CONFIG_SAMPLE_TRACE_ARRAY) += sample-trace-array.o
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
#include <linux/module.h>
3+
#include <linux/kthread.h>
4+
#include <linux/ftrace.h>
5+
#include <asm/asm-offsets.h>
6+
7+
void my_direct_func1(unsigned long ip)
8+
{
9+
trace_printk("my direct func1 ip %lx\n", ip);
10+
}
11+
12+
void my_direct_func2(unsigned long ip)
13+
{
14+
trace_printk("my direct func2 ip %lx\n", ip);
15+
}
16+
17+
extern void my_tramp1(void *);
18+
extern void my_tramp2(void *);
19+
20+
#ifdef CONFIG_X86_64
21+
22+
asm (
23+
" .pushsection .text, \"ax\", @progbits\n"
24+
" .type my_tramp1, @function\n"
25+
" .globl my_tramp1\n"
26+
" my_tramp1:"
27+
" pushq %rbp\n"
28+
" movq %rsp, %rbp\n"
29+
" pushq %rdi\n"
30+
" movq 8(%rbp), %rdi\n"
31+
" call my_direct_func1\n"
32+
" popq %rdi\n"
33+
" leave\n"
34+
" ret\n"
35+
" .size my_tramp1, .-my_tramp1\n"
36+
" .type my_tramp2, @function\n"
37+
"\n"
38+
" .globl my_tramp2\n"
39+
" my_tramp2:"
40+
" pushq %rbp\n"
41+
" movq %rsp, %rbp\n"
42+
" pushq %rdi\n"
43+
" movq 8(%rbp), %rdi\n"
44+
" call my_direct_func2\n"
45+
" popq %rdi\n"
46+
" leave\n"
47+
" ret\n"
48+
" .size my_tramp2, .-my_tramp2\n"
49+
" .popsection\n"
50+
);
51+
52+
#endif /* CONFIG_X86_64 */
53+
54+
#ifdef CONFIG_S390
55+
56+
asm (
57+
" .pushsection .text, \"ax\", @progbits\n"
58+
" .type my_tramp1, @function\n"
59+
" .globl my_tramp1\n"
60+
" my_tramp1:"
61+
" lgr %r1,%r15\n"
62+
" stmg %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"
63+
" stg %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"
64+
" aghi %r15,"__stringify(-STACK_FRAME_OVERHEAD)"\n"
65+
" stg %r1,"__stringify(__SF_BACKCHAIN)"(%r15)\n"
66+
" lgr %r2,%r0\n"
67+
" brasl %r14,my_direct_func1\n"
68+
" aghi %r15,"__stringify(STACK_FRAME_OVERHEAD)"\n"
69+
" lmg %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"
70+
" lg %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"
71+
" lgr %r1,%r0\n"
72+
" br %r1\n"
73+
" .size my_tramp1, .-my_tramp1\n"
74+
"\n"
75+
" .type my_tramp2, @function\n"
76+
" .globl my_tramp2\n"
77+
" my_tramp2:"
78+
" lgr %r1,%r15\n"
79+
" stmg %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"
80+
" stg %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"
81+
" aghi %r15,"__stringify(-STACK_FRAME_OVERHEAD)"\n"
82+
" stg %r1,"__stringify(__SF_BACKCHAIN)"(%r15)\n"
83+
" lgr %r2,%r0\n"
84+
" brasl %r14,my_direct_func2\n"
85+
" aghi %r15,"__stringify(STACK_FRAME_OVERHEAD)"\n"
86+
" lmg %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"
87+
" lg %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"
88+
" lgr %r1,%r0\n"
89+
" br %r1\n"
90+
" .size my_tramp2, .-my_tramp2\n"
91+
" .popsection\n"
92+
);
93+
94+
#endif /* CONFIG_S390 */
95+
96+
static unsigned long my_tramp = (unsigned long)my_tramp1;
97+
static unsigned long tramps[2] = {
98+
(unsigned long)my_tramp1,
99+
(unsigned long)my_tramp2,
100+
};
101+
102+
static struct ftrace_ops direct;
103+
104+
static int simple_thread(void *arg)
105+
{
106+
static int t;
107+
int ret = 0;
108+
109+
while (!kthread_should_stop()) {
110+
set_current_state(TASK_INTERRUPTIBLE);
111+
schedule_timeout(2 * HZ);
112+
113+
if (ret)
114+
continue;
115+
t ^= 1;
116+
ret = modify_ftrace_direct_multi(&direct, tramps[t]);
117+
if (!ret)
118+
my_tramp = tramps[t];
119+
WARN_ON_ONCE(ret);
120+
}
121+
122+
return 0;
123+
}
124+
125+
static struct task_struct *simple_tsk;
126+
127+
static int __init ftrace_direct_multi_init(void)
128+
{
129+
int ret;
130+
131+
ftrace_set_filter_ip(&direct, (unsigned long) wake_up_process, 0, 0);
132+
ftrace_set_filter_ip(&direct, (unsigned long) schedule, 0, 0);
133+
134+
ret = register_ftrace_direct_multi(&direct, my_tramp);
135+
136+
if (!ret)
137+
simple_tsk = kthread_run(simple_thread, NULL, "event-sample-fn");
138+
return ret;
139+
}
140+
141+
static void __exit ftrace_direct_multi_exit(void)
142+
{
143+
kthread_stop(simple_tsk);
144+
unregister_ftrace_direct_multi(&direct, my_tramp);
145+
}
146+
147+
module_init(ftrace_direct_multi_init);
148+
module_exit(ftrace_direct_multi_exit);
149+
150+
MODULE_AUTHOR("Jiri Olsa");
151+
MODULE_DESCRIPTION("Example use case of using modify_ftrace_direct_multi()");
152+
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)