b4d6de9b6f
Thanks to Otavio Salvador for bringing up this issue. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
102 lines
2.4 KiB
C
102 lines
2.4 KiB
C
/*
|
|
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");
|