| /* |
| Copyright (C) 2007 Arnaldo Carvalho de Melo <acme@redhat.com> |
| |
| This program is free software; you can redistribute it and/or modify it |
| under the terms of version 2 of the GNU General Public License as |
| published by the Free Software Foundation. |
| */ |
| #include <linux/kernel.h> |
| #include <linux/debugfs.h> |
| #include <linux/fs.h> |
| #include <linux/percpu.h> |
| #include <linux/relay.h> |
| #include <linux/sched.h> |
| #include <linux/string.h> |
| #include <linux/module.h> |
| #include "ctracer_relay.h" |
| |
| static struct rchan *ctracer__rchan; |
| |
| static int ctracer__subbuf_start_callback(struct rchan_buf *buf, void *subbuf, |
| void *prev_subbuf, |
| size_t prev_padding) |
| { |
| static int warned; |
| if (!relay_buf_full(buf)) |
| return 1; |
| if (!warned) { |
| warned = 1; |
| printk("relay_buf_full!\n"); |
| } |
| return 0; |
| } |
| |
| static struct dentry *ctracer__create_buf_file_callback(const char *filename, |
| struct dentry *parent, |
| int mode, |
| struct rchan_buf *buf, |
| int *is_global) |
| { |
| return debugfs_create_file(filename, mode, parent, buf, |
| &relay_file_operations); |
| } |
| |
| static int ctracer__remove_buf_file_callback(struct dentry *dentry) |
| { |
| debugfs_remove(dentry); |
| return 0; |
| } |
| |
| static struct rchan_callbacks ctracer__relay_callbacks = { |
| .subbuf_start = ctracer__subbuf_start_callback, |
| .create_buf_file = ctracer__create_buf_file_callback, |
| .remove_buf_file = ctracer__remove_buf_file_callback, |
| }; |
| |
| extern void ctracer__class_state(const void *from, void *to); |
| |
| void ctracer__method_hook(const unsigned long long now, |
| const int probe_type, |
| const unsigned long long function_id, |
| const void *object, const int state_len) |
| { |
| if (object != NULL) { |
| void *t = relay_reserve(ctracer__rchan, |
| sizeof(struct trace_entry) + state_len); |
| |
| if (t != NULL) { |
| struct trace_entry *entry = t; |
| |
| entry->nsec = now; |
| entry->probe_type = probe_type; |
| entry->object = object; |
| entry->function_id = function_id; |
| ctracer__class_state(object, t + sizeof(*entry)); |
| } |
| } |
| } |
| |
| EXPORT_SYMBOL_GPL(ctracer__method_hook); |
| |
| static int __init ctracer__relay_init(void) |
| { |
| ctracer__rchan = relay_open("ctracer", NULL, 512 * 1024, 64, |
| &ctracer__relay_callbacks, NULL); |
| if (ctracer__rchan == NULL) { |
| pr_info("ctracer: couldn't create the relay\n"); |
| return -1; |
| } |
| return 0; |
| } |
| |
| module_init(ctracer__relay_init); |
| |
| static void __exit ctracer__relay_exit(void) |
| { |
| relay_close(ctracer__rchan); |
| } |
| |
| module_exit(ctracer__relay_exit); |
| |
| MODULE_LICENSE("GPL"); |