History

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

Linus Torvalds committed 4 years ago

Commit 257dcf22 parents 0d21e66 c24be245 files · +242 −6Browse files

Unified · Split

5 files
  1. fs/tracefs/inode.c +76 −0
  2. kernel/trace/ftrace.c +7 −1
  3. kernel/trace/trace_events_synth.c +6 −5
  4. samples/ftrace/Makefile +1 −0
  5. samples/ftrace/ftrace-direct-multi-modify.c +152 −0
fs/tracefs/inode.c+76−0
@@ -161,6 +161,77 @@ struct tracefs_fs_info { · 160 unmodified lines
161 struct tracefs_mount_opts mount_opts;161 struct tracefs_mount_opts mount_opts;
162};162};
163 163
164static 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 */
178static 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);
187repeat:
188 next = this_parent->d_subdirs.next;
189resume:
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();
212ascend:
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
164static int tracefs_parse_options(char *data, struct tracefs_mount_opts *opts)235static int tracefs_parse_options(char *data, struct tracefs_mount_opts *opts)
165{236{
166 substring_t args[MAX_OPT_ARGS];237 substring_t args[MAX_OPT_ARGS];
@@ -193,6 +264,7 @@ static int tracefs_parse_options(char *data, struct tracefs_mount_opts *opts) · 26 unmodified lines
193 if (!gid_valid(gid))264 if (!gid_valid(gid))
194 return -EINVAL;265 return -EINVAL;
195 opts->gid = gid;266 opts->gid = gid;
267 set_gid(tracefs_mount->mnt_root, gid);
196 break;268 break;
197 case Opt_mode:269 case Opt_mode:
198 if (match_octal(&args[0], &option))270 if (match_octal(&args[0], &option))
@@ -414,6 +486,8 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode, · 215 unmodified lines
414 inode->i_mode = mode;486 inode->i_mode = mode;
415 inode->i_fop = fops ? fops : &tracefs_file_operations;487 inode->i_fop = fops ? fops : &tracefs_file_operations;
416 inode->i_private = data;488 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;
417 d_instantiate(dentry, inode);491 d_instantiate(dentry, inode);
418 fsnotify_create(dentry->d_parent->d_inode, dentry);492 fsnotify_create(dentry->d_parent->d_inode, dentry);
419 return end_creating(dentry);493 return end_creating(dentry);
@@ -436,6 +510,8 @@ static struct dentry *__create_dir(const char *name, struct dentry *parent, · 16 unmodified lines
436 inode->i_mode = S_IFDIR | S_IRWXU | S_IRUSR| S_IRGRP | S_IXUSR | S_IXGRP;510 inode->i_mode = S_IFDIR | S_IRWXU | S_IRUSR| S_IRGRP | S_IXUSR | S_IXGRP;
437 inode->i_op = ops;511 inode->i_op = ops;
438 inode->i_fop = &simple_dir_operations;512 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;
439 515
440 /* directory inodes start off with i_nlink == 2 (for "." entry) */516 /* directory inodes start off with i_nlink == 2 (for "." entry) */
441 inc_nlink(inode);517 inc_nlink(inode);
kernel/trace/ftrace.c+7−1
@@ -5217,6 +5217,7 @@ int unregister_ftrace_direct(unsigned long ip, unsigned long addr) · 5216 unmodified lines
5217{5217{
5218 struct ftrace_direct_func *direct;5218 struct ftrace_direct_func *direct;
5219 struct ftrace_func_entry *entry;5219 struct ftrace_func_entry *entry;
5220 struct ftrace_hash *hash;
5220 int ret = -ENODEV;5221 int ret = -ENODEV;
5221 5222
5222 mutex_lock(&direct_mutex);5223 mutex_lock(&direct_mutex);
@@ -5225,7 +5226,8 @@ int unregister_ftrace_direct(unsigned long ip, unsigned long addr) · 2 unmodified lines
5225 if (!entry)5226 if (!entry)
5226 goto out_unlock;5227 goto out_unlock;
5227 5228
5228 if (direct_functions->count == 1)5229 hash = direct_ops.func_hash->filter_hash;
5230 if (hash->count == 1)
5229 unregister_ftrace_function(&direct_ops);5231 unregister_ftrace_function(&direct_ops);
5230 5232
5231 ret = ftrace_set_filter_ip(&direct_ops, ip, 1, 0);5233 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) · 308 unmodified lines
5540 err = unregister_ftrace_function(ops);5542 err = unregister_ftrace_function(ops);
5541 remove_direct_functions_hash(hash, addr);5543 remove_direct_functions_hash(hash, addr);
5542 mutex_unlock(&direct_mutex);5544 mutex_unlock(&direct_mutex);
5545
5546 /* cleanup for possible another register call */
5547 ops->func = NULL;
5548 ops->trampoline = 0;
5543 return err;5549 return err;
5544}5550}
5545EXPORT_SYMBOL_GPL(unregister_ftrace_direct_multi);5551EXPORT_SYMBOL_GPL(unregister_ftrace_direct_multi);
kernel/trace/trace_events_synth.c+6−5
@@ -1237,9 +1237,8 @@ static int __create_synth_event(const char *name, const char *raw_fields) · 1236 unmodified lines
1237 argv + consumed, &consumed,1237 argv + consumed, &consumed,
1238 &field_version);1238 &field_version);
1239 if (IS_ERR(field)) {1239 if (IS_ERR(field)) {
1240 argv_free(argv);
1241 ret = PTR_ERR(field);1240 ret = PTR_ERR(field);
1242 goto err;1241 goto err_free_arg;
1243 }1242 }
1244 1243
1245 /*1244 /*
@@ -1262,18 +1261,19 @@ static int __create_synth_event(const char *name, const char *raw_fields) · 16 unmodified lines
1262 if (cmd_version > 1 && n_fields_this_loop >= 1) {1261 if (cmd_version > 1 && n_fields_this_loop >= 1) {
1263 synth_err(SYNTH_ERR_INVALID_CMD, errpos(field_str));1262 synth_err(SYNTH_ERR_INVALID_CMD, errpos(field_str));
1264 ret = -EINVAL;1263 ret = -EINVAL;
1265 goto err;1264 goto err_free_arg;
1266 }1265 }
1267 1266
1268 fields[n_fields++] = field;1267 fields[n_fields++] = field;
1269 if (n_fields == SYNTH_FIELDS_MAX) {1268 if (n_fields == SYNTH_FIELDS_MAX) {
1270 synth_err(SYNTH_ERR_TOO_MANY_FIELDS, 0);1269 synth_err(SYNTH_ERR_TOO_MANY_FIELDS, 0);
1271 ret = -EINVAL;1270 ret = -EINVAL;
1272 goto err;1271 goto err_free_arg;
1273 }1272 }
1274 1273
1275 n_fields_this_loop++;1274 n_fields_this_loop++;
1276 }1275 }
1276 argv_free(argv);
1277 1277
1278 if (consumed < argc) {1278 if (consumed < argc) {
1279 synth_err(SYNTH_ERR_INVALID_CMD, 0);1279 synth_err(SYNTH_ERR_INVALID_CMD, 0);
@@ -1281,7 +1281,6 @@ static int __create_synth_event(const char *name, const char *raw_fields) · 1 unmodified line
1281 goto err;1281 goto err;
1282 }1282 }
1283 1283
1284 argv_free(argv);
1285 }1284 }
1286 1285
1287 if (n_fields == 0) {1286 if (n_fields == 0) {
@@ -1307,6 +1306,8 @@ static int __create_synth_event(const char *name, const char *raw_fields) · 19 unmodified lines
1307 kfree(saved_fields);1306 kfree(saved_fields);
1308 1307
1309 return ret;1308 return ret;
1309 err_free_arg:
1310 argv_free(argv);
1310 err:1311 err:
1311 for (i = 0; i < n_fields; i++)1312 for (i = 0; i < n_fields; i++)
1312 free_synth_field(fields[i]);1313 free_synth_field(fields[i]);
samples/ftrace/Makefile+1−0
@@ -4,6 +4,7 @@ obj-$(CONFIG_SAMPLE_FTRACE_DIRECT) += ftrace-direct.o · 3 unmodified lines
4obj-$(CONFIG_SAMPLE_FTRACE_DIRECT) += ftrace-direct-too.o4obj-$(CONFIG_SAMPLE_FTRACE_DIRECT) += ftrace-direct-too.o
5obj-$(CONFIG_SAMPLE_FTRACE_DIRECT) += ftrace-direct-modify.o5obj-$(CONFIG_SAMPLE_FTRACE_DIRECT) += ftrace-direct-modify.o
6obj-$(CONFIG_SAMPLE_FTRACE_DIRECT_MULTI) += ftrace-direct-multi.o6obj-$(CONFIG_SAMPLE_FTRACE_DIRECT_MULTI) += ftrace-direct-multi.o
7obj-$(CONFIG_SAMPLE_FTRACE_DIRECT_MULTI) += ftrace-direct-multi-modify.o
7 8
8CFLAGS_sample-trace-array.o := -I$(src)9CFLAGS_sample-trace-array.o := -I$(src)
9obj-$(CONFIG_SAMPLE_TRACE_ARRAY) += sample-trace-array.o10obj-$(CONFIG_SAMPLE_TRACE_ARRAY) += sample-trace-array.o
samples/ftrace/ftrace-direct-multi-modify.c+152−0
@@ -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
7void my_direct_func1(unsigned long ip)
8{
9 trace_printk("my direct func1 ip %lx\n", ip);
10}
11
12void my_direct_func2(unsigned long ip)
13{
14 trace_printk("my direct func2 ip %lx\n", ip);
15}
16
17extern void my_tramp1(void *);
18extern void my_tramp2(void *);
19
20#ifdef CONFIG_X86_64
21
22asm (
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
56asm (
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
96static unsigned long my_tramp = (unsigned long)my_tramp1;
97static unsigned long tramps[2] = {
98 (unsigned long)my_tramp1,
99 (unsigned long)my_tramp2,
100};
101
102static struct ftrace_ops direct;
103
104static 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
125static struct task_struct *simple_tsk;
126
127static 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
141static void __exit ftrace_direct_multi_exit(void)
142{
143 kthread_stop(simple_tsk);
144 unregister_ftrace_direct_multi(&direct, my_tramp);
145}
146
147module_init(ftrace_direct_multi_init);
148module_exit(ftrace_direct_multi_exit);
149
150MODULE_AUTHOR("Jiri Olsa");
151MODULE_DESCRIPTION("Example use case of using modify_ftrace_direct_multi()");
152MODULE_LICENSE("GPL");

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t