Skip to content

Commit ac471a4

Browse files
committed
Add gen_kernel_events procfile for on-demand kernel tracepoint
Signed-off-by: Francis Deslauriers <francis.deslauriers@efficios.com>
1 parent cbc1904 commit ac471a4

File tree

2 files changed

+323
-0
lines changed

2 files changed

+323
-0
lines changed

instrumentation/events/lttng-module/lttng-test.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,22 @@ LTTNG_TRACEPOINT_EVENT(lttng_test_filter_event,
4848
)
4949
)
5050

51+
LTTNG_TRACEPOINT_EVENT(lttng_test_event_a,
52+
TP_PROTO(int id),
53+
TP_ARGS(id),
54+
TP_FIELDS(
55+
ctf_integer(int, id, id)
56+
)
57+
)
58+
59+
LTTNG_TRACEPOINT_EVENT(lttng_test_event_b,
60+
TP_PROTO(int id),
61+
TP_ARGS(id),
62+
TP_FIELDS(
63+
ctf_integer(int, id, id)
64+
)
65+
)
66+
5167
#endif /* LTTNG_TRACE_LTTNG_TEST_H */
5268

5369
/* This part must be outside protection */

tests/probes/lttng-test.c

Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@
2020
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2121
*/
2222

23+
#include <linux/ctype.h>
2324
#include <linux/init.h>
2425
#include <linux/module.h>
2526
#include <linux/proc_fs.h>
27+
#include <linux/seq_file.h>
28+
#include <linux/slab.h>
2629
#include <linux/byteorder/generic.h>
2730

2831
#include <lttng-events.h>
@@ -39,12 +42,37 @@
3942
#include <instrumentation/events/lttng-module/lttng-test.h>
4043

4144
DEFINE_TRACE(lttng_test_filter_event);
45+
DEFINE_TRACE(lttng_test_event_a);
46+
DEFINE_TRACE(lttng_test_event_b);
4247

4348
#define LTTNG_TEST_FILTER_EVENT_FILE "lttng-test-filter-event"
49+
#define LTTNG_TEST_PROCFS_DIR "lttng-test"
50+
#define LTTNG_TEST_GENERATE_EVENTS "gen-kernel-events"
4451

4552
#define LTTNG_WRITE_COUNT_MAX 64
53+
#define LTTNG_TEST_SYM_LEN 40
54+
55+
/* Max number of events to generate in one call to avoid DoS */
56+
#define LTTNG_TEST_EVENT_MAX 100
57+
58+
/* The max command length is 3 symbols and 2 spaces */
59+
#define LTTNG_TEST_CMD_LEN ((LTTNG_TEST_SYM_LEN * 3) + 2)
4660

4761
static struct proc_dir_entry *lttng_test_filter_event_dentry;
62+
static struct proc_dir_entry *lttng_test_dentry;
63+
static struct proc_dir_entry *lttng_test_gen_events_dentry;
64+
65+
/**
66+
* lttng_test_method: defines a method, its argument and a run callback.
67+
* method_name: Name of the method
68+
* arg_name: Name of the argument (for usage message)
69+
* (*run): Function to call
70+
*/
71+
struct lttng_test_method {
72+
char method_name[LTTNG_TEST_SYM_LEN];
73+
char arg_name[LTTNG_TEST_SYM_LEN];
74+
int (*run)(char *arg, int id);
75+
};
4876

4977
static
5078
void trace_test_event(unsigned int nr_iter)
@@ -94,13 +122,266 @@ static const struct file_operations lttng_test_filter_event_operations = {
94122
.write = lttng_test_filter_event_write,
95123
};
96124

125+
/**
126+
* event_a: triggers $arg lttng_test_event_a events
127+
* @arg: string containing the number of event to generate
128+
* @id: Unique identifier of the caller
129+
*
130+
* Returns 0 on success and a negative value on parsing error
131+
*/
132+
static int event_a(char *arg, int id)
133+
{
134+
int i, ret;
135+
unsigned long iter;
136+
137+
ret = kstrtoul(arg, 10, &iter);
138+
if (ret) {
139+
printk(KERN_ERR "Failed to parse %s arg", __func__);
140+
goto error;
141+
}
142+
143+
if (iter > LTTNG_TEST_EVENT_MAX) {
144+
printk(KERN_ERR "Number of iteration (%lu) exceeding maximum ", iter);
145+
ret = -EDOM;
146+
goto error;
147+
}
148+
149+
ret = 0;
150+
for (i = 0; i < iter; i++) {
151+
trace_lttng_test_event_a(id);
152+
}
153+
154+
error:
155+
return ret;
156+
}
157+
158+
/**
159+
* event_b: triggers $arg lttng_test_event_b events
160+
* @arg: string containing the number of event to generate
161+
* @id: Unique identifier of the caller
162+
*
163+
* Returns 0 on success and a negative value on parsing error
164+
*/
165+
static int event_b(char *arg, int id)
166+
{
167+
int i, ret;
168+
unsigned long iter;
169+
170+
ret = kstrtoul(arg, 10, &iter);
171+
if (ret) {
172+
printk(KERN_ERR "Failed to parse %s arg", __func__);
173+
goto error;
174+
}
175+
176+
if (iter > LTTNG_TEST_EVENT_MAX) {
177+
printk(KERN_ERR "Number of iteration (%lu) exceeding maximum ", iter);
178+
ret = -EDOM;
179+
goto error;
180+
}
181+
182+
ret = 0;
183+
for (i = 0; i < iter; i++) {
184+
trace_lttng_test_event_b(id);
185+
}
186+
187+
error:
188+
return ret;
189+
}
190+
191+
/**
192+
* Array of method descriptions.
193+
*/
194+
static struct lttng_test_method test_methods[] = {
195+
{"event_a", "count", &event_a},
196+
{"event_b", "count", &event_b},
197+
};
198+
199+
/*
200+
* Returns the number of space-delimited words in a given string. Returns -1, if
201+
* non-ascii byte is found.
202+
*/
203+
static int count_word_in_str(char *str, size_t len)
204+
{
205+
int i, count, prev_is_space;
206+
207+
count = 0;
208+
prev_is_space = 1;
209+
for (i = 0; i < len && str[i] != '\0'; i++) {
210+
if (!isascii(str[i])) {
211+
count = -1;
212+
break;
213+
}
214+
215+
switch (str[i]) {
216+
case ' ':
217+
prev_is_space = 1;
218+
break;
219+
default:
220+
if (prev_is_space) {
221+
count++;
222+
prev_is_space = 0;
223+
}
224+
break;
225+
}
226+
}
227+
return count;
228+
}
229+
230+
/**
231+
* lttng_test_gen_events_write: run the speficied method with the specified
232+
* argument. The accepted syntax is:`<method_name> <arg> <unique-id>`
233+
* @file: file pointer
234+
* @user_buf: user string
235+
* @count: length to copy
236+
* @ppos: current position in the file
237+
*
238+
* Return -1 on error, with EFAULT errno. Returns count on success to report a
239+
* successful write to the caller.
240+
*
241+
*/
242+
static
243+
ssize_t lttng_test_gen_events_write(struct file *file, const char __user *user_buf,
244+
size_t count, loff_t *ppos)
245+
{
246+
char *buf, *ptr;
247+
char *user_method, *user_arg, *user_id;
248+
int i, ret;
249+
size_t buf_len;
250+
unsigned long id;
251+
252+
if (count > LTTNG_TEST_CMD_LEN) {
253+
ret = -EINVAL;
254+
goto kmalloc_err;
255+
}
256+
buf_len = count;
257+
258+
buf = kmalloc(sizeof(char) * count, GFP_KERNEL);
259+
if (!buf) {
260+
ret = -ENOMEM;
261+
goto kmalloc_err;
262+
}
263+
ret = copy_from_user(buf, user_buf, count);
264+
if (ret) {
265+
printk(KERN_ERR "copy from user error\n");
266+
ret = -EFAULT;
267+
goto error;
268+
}
269+
270+
buf[count-1] = '\0';
271+
272+
/* Check that the string is of the right format */
273+
if (count_word_in_str(buf, count) != 3) {
274+
printk(KERN_ERR "lttng_gen_kernel_event wrong input format");
275+
ret = -EINVAL;
276+
goto error;
277+
}
278+
279+
/* Extract the three fields for the user request */
280+
ptr = buf;
281+
user_method = strsep(&ptr, " ");
282+
if (!user_method) {
283+
printk(KERN_ERR "strsep returned NULL");
284+
ret = -EINVAL;
285+
goto error;
286+
}
287+
288+
if (strlen(user_method) >= LTTNG_TEST_SYM_LEN) {
289+
ret = -EINVAL;
290+
goto error;
291+
}
292+
293+
user_arg = strsep(&ptr, " ");
294+
if (!user_arg) {
295+
printk(KERN_ERR "strsep returned NULL");
296+
ret = -EINVAL;
297+
goto error;
298+
}
299+
300+
if (strlen(user_arg) >= LTTNG_TEST_SYM_LEN) {
301+
ret = -EINVAL;
302+
goto error;
303+
}
304+
305+
user_id = ptr;
306+
if (strlen(user_id) >= (LTTNG_TEST_SYM_LEN)) {
307+
ret = -EINVAL;
308+
goto error;
309+
}
310+
/* Convert the uuid from string to a int */
311+
ret = kstrtoul(user_id, 10, &id);
312+
if (ret) {
313+
printk(KERN_ERR "Failed to parse method uuid");
314+
ret = -EINVAL;
315+
goto error;
316+
}
317+
318+
/*
319+
* Iterate over all the methods and compare the name of the
320+
* method and the string from the user
321+
*/
322+
ret = -EINVAL;
323+
for (i = 0; i < ARRAY_SIZE(test_methods); i++) {
324+
if (strcmp(user_method, test_methods[i].method_name) != 0) {
325+
continue;
326+
}
327+
328+
/*
329+
* Once a match is found, the method is called
330+
* and the function returns
331+
*/
332+
ret = test_methods[i].run(user_arg, id);
333+
334+
/*
335+
* If the call is successful, return the number
336+
* of count passed to write to return success to
337+
* the caller.
338+
*/
339+
if (!ret) {
340+
ret = count;
341+
}
342+
break;
343+
}
344+
error:
345+
kfree(buf);
346+
kmalloc_err:
347+
return ret;
348+
}
349+
350+
static int lttng_test_gen_events_show(struct seq_file *m, void *v)
351+
{
352+
int i;
353+
seq_printf(m, "Available methods:\n");
354+
for (i = 0; i < ARRAY_SIZE(test_methods); i++) {
355+
seq_printf(m, "%s %s unique-id\n", test_methods[i].method_name,
356+
test_methods[i].arg_name);
357+
}
358+
return 0;
359+
}
360+
361+
static int lttng_test_gen_events_open(struct inode *inode, struct file *file)
362+
{
363+
return single_open(file, lttng_test_gen_events_show, NULL);
364+
}
365+
366+
static const struct file_operations lttng_test_gen_events_operations = {
367+
.write = lttng_test_gen_events_write,
368+
.open = lttng_test_gen_events_open,
369+
.read = seq_read,
370+
.llseek = seq_lseek,
371+
.release = single_release,
372+
};
373+
97374
static
98375
int __init lttng_test_init(void)
99376
{
100377
int ret = 0;
101378

102379
(void) wrapper_lttng_fixup_sig(THIS_MODULE);
103380
wrapper_vmalloc_sync_all();
381+
/*
382+
* The lttng_test_filter_event file is left in `/proc`
383+
* for backward compatibility reason.
384+
*/
104385
lttng_test_filter_event_dentry =
105386
proc_create_data(LTTNG_TEST_FILTER_EVENT_FILE,
106387
S_IRUGO | S_IWUGO, NULL,
@@ -110,12 +391,34 @@ int __init lttng_test_init(void)
110391
ret = -ENOMEM;
111392
goto error;
112393
}
394+
/* Create lttng-test proc directory */
395+
lttng_test_dentry = proc_mkdir(LTTNG_TEST_PROCFS_DIR, NULL);
396+
if (!lttng_test_dentry) {
397+
printk(KERN_ERR "Error creating LTTng test directory\n");
398+
ret = -ENOMEM;
399+
goto error_proc_mkdir;
400+
}
401+
402+
lttng_test_gen_events_dentry =
403+
proc_create_data(LTTNG_TEST_GENERATE_EVENTS,
404+
S_IRUGO | S_IWUGO, lttng_test_dentry,
405+
&lttng_test_gen_events_operations, NULL);
406+
if (!lttng_test_gen_events_dentry) {
407+
printk(KERN_ERR "Error creating LTTng gen-events file\n");
408+
ret = -ENOMEM;
409+
goto error_proc_gen_events;
410+
}
411+
113412
ret = __lttng_events_init__lttng_test();
114413
if (ret)
115414
goto error_events;
116415
return ret;
117416

118417
error_events:
418+
remove_proc_entry(LTTNG_TEST_GENERATE_EVENTS, lttng_test_dentry);
419+
error_proc_gen_events:
420+
remove_proc_entry(LTTNG_TEST_PROCFS_DIR, NULL);
421+
error_proc_mkdir:
119422
remove_proc_entry(LTTNG_TEST_FILTER_EVENT_FILE, NULL);
120423
error:
121424
return ret;
@@ -129,6 +432,10 @@ void __exit lttng_test_exit(void)
129432
__lttng_events_exit__lttng_test();
130433
if (lttng_test_filter_event_dentry)
131434
remove_proc_entry(LTTNG_TEST_FILTER_EVENT_FILE, NULL);
435+
if (lttng_test_gen_events_dentry && lttng_test_dentry)
436+
remove_proc_entry(LTTNG_TEST_GENERATE_EVENTS, lttng_test_dentry);
437+
if (lttng_test_dentry)
438+
remove_proc_entry(LTTNG_TEST_PROCFS_DIR, NULL);
132439
}
133440

134441
module_exit(lttng_test_exit);

0 commit comments

Comments
 (0)