int lttng_abi_create_session(void)
{
struct ltt_session *session;
- struct file *session_filp;
+ struct file *session_file;
int session_fd;
session = ltt_session_create();
ret = session_fd;
goto fd_error;
}
- session_filp = anon_inode_getfile("[lttng_session]",
+ session_file = anon_inode_getfile("[lttng_session]",
<tng_session_fops,
session, O_RDWR);
- if (IS_ERR(session_filp)) {
- ret = PTR_ERR(session_filp);
+ if (IS_ERR(session_file)) {
+ ret = PTR_ERR(session_file);
goto file_error;
}
- session->file = session_filp;
- fd_install(session_fd, session_filp);
+ session->file = session_file;
+ fd_install(session_fd, session_file);
return session_fd;
file_error:
/**
* lttng_ioctl - lttng syscall through ioctl
*
- * @filp: the file
+ * @file: the file
* @cmd: the command
* @arg: command arg
*
* The returned session will be deleted when its file descriptor is closed.
*/
static
-long lttng_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+long lttng_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
switch (cmd) {
case LTTNG_SESSION:
#endif
}
-int lttng_abi_create_channel(struct file *session_filp,
+int lttng_abi_create_channel(struct file *session_file,
struct lttng_channel __user *uchan_param)
{
- struct ltt_session *session = session_filp->private_data;
+ struct ltt_session *session = session_file->private_data;
struct ltt_channel *chan;
- struct file *chan_filp;
+ struct file *chan_file;
struct lttng_channel chan_param;
int chan_fd;
int ret = 0;
ret = chan_fd;
goto fd_error;
}
- chan_filp = anon_inode_getfile("[lttng_channel]",
+ chan_file = anon_inode_getfile("[lttng_channel]",
<tng_channel_fops,
NULL, O_RDWR);
- if (IS_ERR(chan_filp)) {
- ret = PTR_ERR(chan_filp);
+ if (IS_ERR(chan_file)) {
+ ret = PTR_ERR(chan_file);
goto file_error;
}
/*
ret = -ENOMEM;
goto chan_error;
}
- channel->file = chan_filp;
- chan_filp->private_data = chan;
- fd_install(chan_fd, chan_filp);
+ channel->file = chan_file;
+ chan_file->private_data = chan;
+ fd_install(chan_fd, chan_file);
/* The channel created holds a reference on the session */
- atomic_inc(&session_filp->f_count);
+ atomic_inc(&session_file->f_count);
return chan_fd;
chan_error:
- fput(chan_filp);
+ fput(chan_file);
file_error:
put_unused_fd(chan_fd);
fd_error:
/**
* lttng_session_ioctl - lttng session fd ioctl
*
- * @filp: the file
+ * @file: the file
* @cmd: the command
* @arg: command arg
*
* The returned channel will be deleted when its file descriptor is closed.
*/
static
-long lttng_session_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+long lttng_session_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
+ struct ltt_session *session = file->private_data;
+
switch (cmd) {
case LTTNG_CHANNEL:
- return lttng_abi_create_channel(filp, (struct lttng_channel __user *)arg);
+ return lttng_abi_create_channel(file, (struct lttng_channel __user *)arg);
+ case LTTNG_SESSION_START:
+ return ltt_session_start(session);
+ case LTTNG_SESSION_STOP:
+ return ltt_session_stop(session);
+ case LTTNG_SESSION_FINALIZE:
+ return ltt_session_finalize(session);
default:
return -ENOIOCTLCMD;
}
}
static
-int lttng_abi_open_stream(struct file *channel_filp)
+int lttng_abi_open_stream(struct file *channel_file)
{
- struct ltt_channel *channel = channel_filp->private_data;
+ struct ltt_channel *channel = channel_file->private_data;
struct lib_ring_buffer *buf;
int stream_fd, ret;
ret = stream_fd;
goto fd_error;
}
- stream_filp = anon_inode_getfile("[lttng_stream]",
+ stream_file = anon_inode_getfile("[lttng_stream]",
&lib_ring_buffer_file_operations,
buf, O_RDWR);
- if (IS_ERR(stream_filp)) {
- ret = PTR_ERR(stream_filp);
+ if (IS_ERR(stream_file)) {
+ ret = PTR_ERR(stream_file);
goto file_error;
}
- fd_install(stream_fd, stream_filp);
+ fd_install(stream_fd, stream_file);
/* The stream holds a reference on the channel */
- atomic_inc(&channel_filp->f_count);
+ atomic_inc(&channel_file->f_count);
return stream_fd;
file_error:
}
static
-int lttng_abi_create_event(struct file *channel_filp,
+int lttng_abi_create_event(struct file *channel_file,
struct lttng_event __user *uevent_param)
{
- struct ltt_channel *channel = channel_filp->private_data;
+ struct ltt_channel *channel = channel_file->private_data;
struct ltt_event *event;
char *event_name;
struct lttng_event event_param;
ret = event_fd;
goto fd_error;
}
- event_filp = anon_inode_getfile("[lttng_event]",
+ event_file = anon_inode_getfile("[lttng_event]",
<tng_event_fops, /* TODO: filter */
NULL, O_RDWR);
- if (IS_ERR(event_filp)) {
- ret = PTR_ERR(event_filp);
+ if (IS_ERR(event_file)) {
+ ret = PTR_ERR(event_file);
goto file_error;
}
/*
goto event_error;
ret = -EEXIST;
}
- event_filp->private_data = event;
- fd_install(event_fd, event_filp);
+ event_file->private_data = event;
+ fd_install(event_fd, event_file);
/* The event holds a reference on the channel */
- atomic_inc(&channel_filp->f_count);
+ atomic_inc(&channel_file->f_count);
kfree(event_name);
return event_fd;
event_error:
- fput(event_filp);
+ fput(event_file);
file_error:
put_unused_fd(event_fd);
fd_error:
/**
* lttng_channel_ioctl - lttng syscall through ioctl
*
- * @filp: the file
+ * @file: the file
* @cmd: the command
* @arg: command arg
*
* Channel and event file descriptors also hold a reference on the session.
*/
static
-long lttng_channel_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+long lttng_channel_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
switch (cmd) {
case LTTNG_STREAM:
- return lttng_abi_open_stream(filp);
+ return lttng_abi_open_stream(file);
case LTTNG_EVENT:
- return lttng_abi_create_event(filp, (struct lttng_event __user *)arg);
+ return lttng_abi_create_event(file, (struct lttng_event __user *)arg);
default:
return -ENOIOCTLCMD;
}
/**
* lttng_channel_poll - lttng stream addition/removal monitoring
*
- * @filp: the file
+ * @file: the file
* @wait: poll table
*/
-unsigned int lttng_channel_poll(struct file *filp, poll_table *wait)
+unsigned int lttng_channel_poll(struct file *file, poll_table *wait)
{
- struct ltt_channel *channel = filp->private_data;
+ struct ltt_channel *channel = file->private_data;
unsigned int mask = 0;
- if (filp->f_mode & FMODE_READ) {
+ if (file->f_mode & FMODE_READ) {
poll_wait_set_exclusive(wait);
- poll_wait(filp, &channel->notify_wait, wait);
+ poll_wait(file, &channel->notify_wait, wait);
/* TODO: identify when the channel is being finalized. */
if (finalized)
*/
#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
#include "ltt-events.h"
static LIST_HEAD(sessions);
+static LIST_HEAD(ltt_transport_list);
static DEFINE_MUTEX(sessions_mutex);
static struct kmem_cache *event_cache;
kfree(session);
}
+int ltt_session_start(struct ltt_session *session)
+{
+ int ret = 0;
+
+ mutex_lock(&sessions_mutex);
+ if (session->active) {
+ ret = -EBUSY;
+ goto end;
+ }
+ session->active = 1;
+ synchronize_trace(); /* Wait for in-flight events to complete */
+end:
+ mutex_unlock(&sessions_mutex);
+ return ret
+}
+
+int ltt_session_stop(struct ltt_session *session)
+{
+ int ret = 0;
+
+ mutex_lock(&sessions_mutex);
+ if (!session->active) {
+ ret = -EBUSY;
+ goto end;
+ }
+ session->active = 0;
+ synchronize_trace(); /* Wait for in-flight events to complete */
+end:
+ mutex_unlock(&sessions_mutex);
+ return ret
+}
+
struct ltt_channel *ltt_channel_create(struct ltt_session *session,
int overwrite, void *buf_addr,
size_t subbuf_size, size_t num_subbuf,
unsigned int read_timer_interval)
{
struct ltt_channel *chan;
+ struct ltt_transport *transport = NULL, *tran_iter;
+ char *transport_name;
mutex_lock(&sessions_mutex);
if (session->active)
goto active; /* Refuse to add channel to active session */
+ transport_name = overwrite ? "relay-overwrite" : "relay-discard";
+ list_for_each_entry(tran_iter, <t_transport_list, node) {
+ if (!strcmp(tran_iter->name, transport_name)) {
+ transport = tran_iter;
+ break;
+ }
+ }
+ if (!transport)
+ goto notransport;
chan = kmalloc(sizeof(struct ltt_channel), GFP_KERNEL);
if (!chan)
- return NULL;
+ goto nomem;
chan->session = session;
init_waitqueue_head(&chan->notify_wait);
-
- /* TODO: create rb channel */
+ transport->ops.channel_create(session, buf_addr, subbuf_size,
+ num_subbuf, switch_timer_interval,
+ read_timer_interval);
list_add(&chan->list, &session->chan);
mutex_unlock(&sessions_mutex);
return chan;
-exist:
+nomem:
+notransport:
active:
mutex_unlock(&sessions_mutex);
return NULL;
*/
int _ltt_channel_destroy(struct ltt_channel *chan)
{
- /* TODO: destroy rb channel */
+ transport->ops.channel_destroy(chan);
list_del(&chan->list);
kfree(chan);
}
kmem_cache_free(event);
}
+/**
+ * ltt_transport_register - LTT transport registration
+ * @transport: transport structure
+ *
+ * Registers a transport which can be used as output to extract the data out of
+ * LTTng. The module calling this registration function must ensure that no
+ * trap-inducing code will be executed by the transport functions. E.g.
+ * vmalloc_sync_all() must be called between a vmalloc and the moment the memory
+ * is made visible to the transport function. This registration acts as a
+ * vmalloc_sync_all. Therefore, only if the module allocates virtual memory
+ * after its registration must it synchronize the TLBs.
+ */
+void ltt_transport_register(struct ltt_transport *transport)
+{
+ /*
+ * Make sure no page fault can be triggered by the module about to be
+ * registered. We deal with this here so we don't have to call
+ * vmalloc_sync_all() in each module's init.
+ */
+ vmalloc_sync_all();
+
+ mutex_lock(&sessions_mutex);
+ list_add_tail(&transport->node, <t_transport_list);
+ mutex_unlock(&sessions_mutex);
+}
+EXPORT_SYMBOL_GPL(ltt_transport_register);
+
+/**
+ * ltt_transport_unregister - LTT transport unregistration
+ * @transport: transport structure
+ */
+void ltt_transport_unregister(struct ltt_transport *transport)
+{
+ mutex_lock(&sessions_mutex);
+ list_del(&transport->node);
+ mutex_unlock(&sessions_mutex);
+}
+EXPORT_SYMBOL_GPL(ltt_transport_unregister);
+
+
static int __init ltt_events_init(void)
{
int ret;
events_cache = KMEM_CACHE(ltt_event, 0);
if (!events_cache)
return -ENOMEM;
-
- /* TODO: show ABI to userspace */
-
return 0;
}
{
struct ltt_session *session, *tmpsession;
- /* TODO: hide ABI from userspace, wait for callers to release refs. */
-
list_for_each_entry_safe(session, tmpsession, &sessions, list)
ltt_session_destroy(session);
kmem_cache_destroy(events_cache);
struct list_head list; /* Session list */
};
+struct ltt_trace_ops {
+ struct channel *(*channel_create)(const char *name,
+ struct ltt_trace *trace,
+ void *buf_addr,
+ size_t subbuf_size, size_t num_subbuf,
+ unsigned int switch_timer_interval,
+ unsigned int read_timer_interval);
+ void (*channel_destroy)(struct channel *chan);
+ struct lib_ring_buffer *(*buffer_read_open)(struct channel *chan);
+ struct lib_ring_buffer *(*buffer_read_close)(struct lib_ring_buffer *buf);
+};
+
+struct ltt_transport {
+ char *name;
+ struct module *owner;
+ struct list_head node;
+ struct ltt_trace_ops ops;
+};
+
struct ltt_session *ltt_session_create(void);
+int ltt_session_start(struct ltt_session *session);
+int ltt_session_stop(struct ltt_session *session);
int ltt_session_destroy(struct ltt_session *session);
struct ltt_channel *ltt_channel_create(struct ltt_session *session,
char *name,
void *filter);
int _ltt_event_destroy(struct ltt_event *event);
+
+void ltt_transport_register(struct ltt_transport *transport);
+void ltt_transport_unregister(struct ltt_transport *transport);
*/
#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/trace-clock.h>
+#include "ltt-events.h"
#include "ltt-tracer.h"
-struct ring_buffer_priv {
- struct dentry *dentry;
-}
-
-struct channel_priv {
- struct ltt_trace *trace;
- struct ring_buffer_priv *buf;
-};
-
static const struct lib_ring_buffer_config client_config;
static u64 client_ring_buffer_clock_read(struct channel *chan)
static int client_buffer_create(struct lib_ring_buffer *buf, void *priv,
int cpu, const char *name)
{
- struct channel_priv *chan_priv = priv;
- struct ring_buffer_priv *buf_priv;
- struct dentry *trace_dentry;
- char *tmpname;
- int ret = 0;
-
- if (client_config.alloc == RING_BUFFER_ALLOC_PER_CPU)
- buf_priv = per_cpu_ptr(chan_priv->buf, cpu);
- else
- buf_priv = chan_priv->buf;
-
- tmpname = kzalloc(NAME_MAX + 1, GFP_KERNEL);
- if (!tmpname) {
- ret = -ENOMEM;
- goto end;
- }
-
- snprintf(tmpname, NAME_MAX, "%s%s_%d",
- (client_config.mode == RING_BUFFER_OVERWRITE) ? "flight-" : "",
- name, cpu);
-
- trace_dentry = chan_priv->trace->dentry.trace_root;
- buf_priv->dentry = debugfs_create_file(tmpname, S_IRUSR, trace_dentry,
- buf,
- &lib_ring_buffer_file_operations);
- if (!buf_priv->dentry) {
- ret = -ENOMEM;
- goto free_name;
- }
-free_name:
- kfree(tmpname);
-end:
- return ret;
}
static void client_buffer_finalize(struct lib_ring_buffer *buf, void *priv, int cpu)
{
- struct channel_priv *chan_priv = priv;
- struct lib_ring_buffer_priv *buf_priv;
-
- if (client_config.alloc == RING_BUFFER_ALLOC_PER_CPU)
- buf_priv = per_cpu_ptr(chan_priv->buf, cpu);
- else
- buf_priv = chan_priv->buf;
-
- debugfs_remove(buf_priv->dentry);
}
static const struct lib_ring_buffer_config client_config = {
};
static
-struct channel *ltt_channel_create(const char *name, struct ltt_trace *trace,
- void *buf_addr,
+struct channel *ltt_channel_create(struct ltt_session *session, void *buf_addr,
size_t subbuf_size, size_t num_subbuf,
unsigned int switch_timer_interval,
unsigned int read_timer_interval)
{
- struct channel *chan;
- struct chan_priv *chan_priv;
-
- chan_priv = kzalloc(sizeof(struct chan_priv), GFP_KERNEL);
- if (!chan_priv)
- return NULL;
- if (client_config.alloc == RING_BUFFER_ALLOC_PER_CPU) {
- chan_priv->buf = alloc_percpu(struct lib_ring_buffer_priv);
- memset(chan_priv->buf, 0, sizeof(*chan_priv->buf));
- } else
- chan_priv->buf = kzalloc(sizeof(*chan_priv->buf), GFP_KERNEL)
- if (!channel_priv->buf)
- goto free_chan_priv;
- chan_priv->trace = trace;
- chan = channel_create(&client_config, name, chan_priv, buf_addr,
+ return channel_create(&client_config, "[lttng]", session, buf_addr,
subbuf_size, num_subbuf, switch_timer_interval,
read_timer_interval);
- if (!chan)
- goto free_buf_priv;
- return chan;
-
-free_buf_priv:
- if (client_config.alloc == RING_BUFFER_ALLOC_PER_CPU)
- free_percpu(chan_priv->buf);
- else
- kfree(chan_priv->buf);
-free_chan_priv:
- kfree(chan_priv);
- return NULL;
}
static
void ltt_channel_destroy(struct channel *chan)
{
- struct chan_priv *chan_priv = channel_get_private(chan);
-
channel_destroy(chan);
- if (client_config.alloc == RING_BUFFER_ALLOC_PER_CPU)
- free_percpu(chan_priv->buf);
- else
- kfree(chan_priv->buf);
- kfree(chan_priv);
}
static
lib_ring_buffer_release_read(buf);
}
-static void ltt_relay_remove_dirs(struct ltt_trace *trace)
-{
- debugfs_remove(trace->dentry.trace_root);
-}
-
-static int ltt_relay_create_dirs(struct ltt_trace *new_trace)
-{
- struct dentry *ltt_root_dentry;
- int ret;
-
- ltt_root_dentry = get_ltt_root();
- if (!ltt_root_dentry)
- return ENOENT;
-
- new_trace->dentry.trace_root = debugfs_create_dir(new_trace->trace_name,
- ltt_root_dentry);
- put_ltt_root();
- if (new_trace->dentry.trace_root == NULL) {
- printk(KERN_ERR "LTT : Trace directory name %s already taken\n",
- new_trace->trace_name);
- return EEXIST;
- }
- return 0;
-}
-
static struct ltt_transport ltt_relay_transport = {
.name = "relay-" RING_BUFFER_MODE_TEMPLATE_STRING,
.owner = THIS_MODULE,
.ops = {
- .create_dirs = ltt_relay_create_dirs,
- .remove_dirs = ltt_relay_remove_dirs,
.create_channel = ltt_channel_create,
.destroy_channel = ltt_channel_destroy,
.buffer_read_open = ltt_buffer_read_open,
unsigned long read;
};
-struct ltt_trace_ops {
- int (*create_dirs) (struct ltt_trace *new_trace);
- void (*remove_dirs) (struct ltt_trace *new_trace);
- struct channel *ltt_channel_create(const char *name,
- struct ltt_trace *trace,
- void *buf_addr,
- size_t subbuf_size, size_t num_subbuf,
- unsigned int switch_timer_interval,
- unsigned int read_timer_interval);
- void ltt_channel_destroy(struct channel *chan);
-};
-
-struct ltt_transport {
- char *name;
- struct module *owner;
- struct list_head node;
- struct ltt_trace_ops ops;
-};
-
enum trace_mode { LTT_TRACE_NORMAL, LTT_TRACE_FLIGHT, LTT_TRACE_HYBRID };
#define CHANNEL_FLAG_ENABLE (1U<<0)
#define CHANNEL_FLAG_OVERWRITE (1U<<1)
+#if 0
/* Per-trace information - each trace/flight recorder represented by one */
struct ltt_trace {
/* First 32 bytes cache-hot cacheline */
wait_queue_head_t kref_wq; /* Place for ltt_trace_destroy to sleep */
char trace_name[NAME_MAX];
} ____cacheline_aligned;
+#endif //0
/*
* Hardcoded event headers
struct module *owner);
extern void ltt_module_unregister(enum ltt_module_function name);
-void ltt_transport_register(struct ltt_transport *transport);
-void ltt_transport_unregister(struct ltt_transport *transport);
-
/* Exported control function */
enum ltt_control_msg {
} new_trace;
};
-int _ltt_trace_setup(const char *trace_name);
-int ltt_trace_setup(const char *trace_name);
-struct ltt_trace *_ltt_trace_find_setup(const char *trace_name);
-int ltt_trace_set_type(const char *trace_name, const char *trace_type);
-int ltt_trace_set_channel_subbufsize(const char *trace_name,
- const char *channel_name,
- unsigned int size);
-int ltt_trace_set_channel_subbufcount(const char *trace_name,
- const char *channel_name,
- unsigned int cnt);
-int ltt_trace_set_channel_switch_timer(const char *trace_name,
- const char *channel_name,
- unsigned long interval);
-int ltt_trace_set_channel_overwrite(const char *trace_name,
- const char *channel_name,
- unsigned int overwrite);
-int ltt_trace_alloc(const char *trace_name);
-int ltt_trace_destroy(const char *trace_name);
-int ltt_trace_start(const char *trace_name);
-int ltt_trace_stop(const char *trace_name);
-
-extern int ltt_control(enum ltt_control_msg msg, const char *trace_name,
- const char *trace_type, union ltt_control_args args);
-
-enum ltt_filter_control_msg {
- LTT_FILTER_DEFAULT_ACCEPT,
- LTT_FILTER_DEFAULT_REJECT
-};
-
-extern int ltt_filter_control(enum ltt_filter_control_msg msg,
- const char *trace_name);
-
-extern struct dentry *get_filter_root(void);
-
void ltt_core_register(int (*function)(u8, void *));
void ltt_core_unregister(void);
-void ltt_release_trace(struct kref *kref);
-void ltt_release_transport(struct kref *kref);
-
extern int ltt_probe_register(struct ltt_available_probe *pdata);
extern int ltt_probe_unregister(struct ltt_available_probe *pdata);
extern int ltt_marker_connect(const char *channel, const char *mname,
const char *pname);
extern void ltt_dump_marker_state(struct ltt_trace *trace);
-void ltt_lock_traces(void);
-void ltt_unlock_traces(void);
-
-extern int ltt_ascii_create_dir(struct ltt_trace *new_trace);
-extern void ltt_ascii_remove_dir(struct ltt_trace *trace);
-extern int ltt_ascii_create(struct ltt_chan *chan);
-extern void ltt_ascii_remove(struct ltt_chan *chan);
-
extern
void ltt_statedump_register_kprobes_dump(void (*callback)(void *call_data));
extern