int lttng_abi_create_session(void)
{
struct ltt_session *session;
- struct file *session_file;
+ struct file *session_filp;
int session_fd;
session = ltt_session_create();
ret = session_fd;
goto fd_error;
}
- session_file = anon_inode_getfile("[lttng_session]",
+ session_filp = anon_inode_getfile("[lttng_session]",
<tng_session_fops,
session, O_RDWR);
- if (IS_ERR(session_file)) {
- ret = PTR_ERR(session_file);
+ if (IS_ERR(session_filp)) {
+ ret = PTR_ERR(session_filp);
goto file_error;
}
- fd_install(session_fd, session_file);
+ fd_install(session_fd, session_filp);
return session_fd;
file_error:
}
}
-#ifdef CONFIG_COMPAT
-static
-long lttng_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-{
- switch (cmd) {
- case LTTNG_SESSION:
- return lttng_abi_create_session();
- default:
- return -ENOIOCTLCMD;
- }
-}
-#endif
-
static const struct file_operations lttng_fops = {
.unlocked_ioctl = lttng_ioctl,
#ifdef CONFIG_COMPAT
- .compat_ioctl = lttng_compat_ioctl,
+ .compat_ioctl = lttng_ioctl,
#endif
}
if (copy_from_user(&chan_param, uchan_param, sizeof(chan_param)))
return -EFAULT;
- chan = ltt_channel_create(session, chan_param->overwrite, NULL,
- chan_param->subbuf_size,
- chan_param->num_subbuf,
- chan_param->switch_timer_interval,
- chan_param->read_timer_interval);
- if (!chan) {
- ret = -ENOMEM;
- goto chan_error;
- }
chan_fd = get_unused_fd_flags(O_RDWR);
if (chan_fd < 0) {
ret = chan_fd;
}
chan_filp = anon_inode_getfile("[lttng_channel]",
<tng_channel_fops,
- chan, O_RDWR);
+ NULL, O_RDWR);
if (IS_ERR(chan_filp)) {
ret = PTR_ERR(chan_filp);
goto file_error;
}
-
+ /*
+ * We tolerate no failure path after channel creation. It will stay
+ * invariant for the rest of the session.
+ */
+ chan = ltt_channel_create(session, chan_param->overwrite, NULL,
+ chan_param->subbuf_size,
+ chan_param->num_subbuf,
+ chan_param->switch_timer_interval,
+ chan_param->read_timer_interval);
+ if (!chan) {
+ ret = -ENOMEM;
+ goto chan_error;
+ }
+ chan_filp->private_data = chan;
+ fd_install(chan_fd, chan_filp);
/* The channel created holds a reference on the session */
atomic_inc(&session_filp->f_count);
return chan_fd;
+chan_error:
+ fput(chan_filp);
file_error:
put_unused_fd(chan_fd);
fd_error:
- ltt_channel_destroy(chan);
-chan_error:
return ret;
}
}
}
-#ifdef CONFIG_COMPAT
+/*
+ * Called when the last file reference is dropped.
+ *
+ * Big fat note: channels and events are invariant for the whole session after
+ * their creation. So this session destruction also destroys all channel and
+ * event structures specific to this session (they are not destroyed when their
+ * individual file is released).
+ */
static
-long lttng_session_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+int lttng_session_release(struct inode *inode, struct file *file)
{
- switch (cmd) {
- case LTTNG_CHANNEL:
- return lttng_abi_create_channel(filp, (struct lttng_channel __user *)arg);
- default:
- return -ENOIOCTLCMD;
- }
+ struct ltt_session *session = file->private_data;
+ return ltt_session_destroy(session);
}
-#endif
static const struct file_operations lttng_session_fops = {
+ .release = lttng_session_release,
.unlocked_ioctl = lttng_session_ioctl,
#ifdef CONFIG_COMPAT
- .compat_ioctl = lttng_session_compat_ioctl,
+ .compat_ioctl = lttng_session_ioctl,
#endif
}
ret = PTR_ERR(stream_filp);
goto file_error;
}
-
+ fd_install(stream_fd, stream_filp);
/* The stream holds a reference on the channel */
atomic_inc(&channel_filp->f_count);
return stream_fd;
goto name_error;
}
event_name[PATH_MAX - 1] = '\0';
- event = ltt_event_create(channel, event_param->itype, event_name, NULL);
- if (!event)
- return -EEXIST;
-
event_fd = get_unused_fd_flags(O_RDWR);
if (event_fd < 0) {
ret = event_fd;
goto fd_error;
}
event_filp = anon_inode_getfile("[lttng_event]",
- <tng_event_fops,
- event, O_RDWR);
+ <tng_event_fops,
+ NULL, O_RDWR);
if (IS_ERR(event_filp)) {
ret = PTR_ERR(event_filp);
goto file_error;
}
-
+ /*
+ * We tolerate no failure path after event creation. It will stay
+ * invariant for the rest of the session.
+ */
+ event = ltt_event_create(channel, event_param->itype, event_name, NULL);
+ if (!event) {
+ goto event_error;
+ ret = -EEXIST;
+ }
+ event_filp->private_data = event;
+ fd_install(event_fd, event_filp);
/* The event holds a reference on the channel */
atomic_inc(&channel_filp->f_count);
+ kfree(event_name);
return event_fd;
+event_error:
+ fput(event_filp);
file_error:
put_unused_fd(event_fd);
fd_error:
- ltt_event_destroy(event);
name_error:
kfree(event_name);
return ret;
}
}
-#ifdef CONFIG_COMPAT
-static
-long lttng_channel_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-{
- switch (cmd) {
- case LTTNG_STREAM:
- return lttng_abi_open_stream(filp);
- case LTTNG_EVENT:
- return lttng_abi_create_event(filp, (struct lttng_event __user *)arg);
- default:
- return -ENOIOCTLCMD;
- }
-}
-#endif
-
/**
* lttng_channel_poll - lttng stream addition/removal monitoring
*
}
static const struct file_operations lttng_channel_fops = {
+ .release = lttng_channel_release,
.poll = lttng_channel_poll,
.unlocked_ioctl = lttng_channel_ioctl,
#ifdef CONFIG_COMPAT
- .compat_ioctl = lttng_channel_compat_ioctl,
+ .compat_ioctl = lttng_channel_ioctl,
#endif
}