Commit | Line | Data |
---|---|---|
1c8284eb MD |
1 | /* |
2 | * ltt/ltt-relay-vfs.c | |
3 | * | |
4 | * (C) Copyright 2009 - Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca) | |
5 | * | |
6 | * LTTng VFS interface. | |
7 | * | |
8 | * Author: | |
9 | * Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca) | |
10 | * | |
11 | * Dual LGPL v2.1/GPL v2 license. | |
12 | */ | |
13 | ||
14 | #include <linux/module.h> | |
15 | #include <linux/fs.h> | |
16 | #include <linux/debugfs.h> | |
17 | #include <linux/ltt-channels.h> | |
18 | #include <asm/atomic.h> | |
19 | ||
20 | #include "ltt-tracer.h" | |
21 | #include "ltt-relay.h" | |
22 | #include "ltt-relay-lockless.h" | |
23 | ||
24 | /** | |
25 | * ltt_open - open file op for ltt files | |
26 | * @inode: opened inode | |
27 | * @file: opened file | |
28 | * | |
29 | * Open implementation. Makes sure only one open instance of a buffer is | |
30 | * done at a given moment. | |
31 | */ | |
32 | static int ltt_open(struct inode *inode, struct file *file) | |
33 | { | |
34 | struct ltt_chanbuf *buf = inode->i_private; | |
35 | int ret; | |
36 | ||
37 | ret = ltt_chanbuf_open_read(buf); | |
38 | if (ret) | |
39 | goto end; | |
40 | ||
41 | file->private_data = buf; | |
42 | ret = nonseekable_open(inode, file); | |
43 | /* | |
44 | * Let LTTng splice operation must believe that the file descriptor is | |
45 | * seekable. This is a temporary fix to follow new checks added to | |
46 | * splice.c. We should probably do the proper thing and implement a | |
47 | * llseek function eventually, which involves modifying the lttng splice | |
48 | * actors accordingly. TODO | |
49 | */ | |
50 | file->f_mode |= FMODE_PREAD; | |
51 | end: | |
52 | return ret; | |
53 | } | |
54 | ||
55 | /** | |
56 | * ltt_release - release file op for ltt files | |
57 | * @inode: opened inode | |
58 | * @file: opened file | |
59 | * | |
60 | * Release implementation. | |
61 | */ | |
62 | static int ltt_release(struct inode *inode, struct file *file) | |
63 | { | |
64 | struct ltt_chanbuf *buf = inode->i_private; | |
65 | ||
66 | ltt_chanbuf_release_read(buf); | |
67 | ||
68 | return 0; | |
69 | } | |
70 | ||
71 | /** | |
72 | * ltt_poll - file op for ltt files | |
73 | * @filp: the file | |
74 | * @wait: poll table | |
75 | * | |
76 | * Poll implementation. | |
77 | */ | |
78 | static unsigned int ltt_poll(struct file *filp, poll_table *wait) | |
79 | { | |
80 | unsigned int mask = 0; | |
81 | struct inode *inode = filp->f_dentry->d_inode; | |
82 | struct ltt_chanbuf *buf = inode->i_private; | |
83 | struct ltt_chan *chan = container_of(buf->a.chan, struct ltt_chan, a); | |
84 | ||
85 | if (filp->f_mode & FMODE_READ) { | |
86 | poll_wait_set_exclusive(wait); | |
87 | poll_wait(filp, &buf->read_wait, wait); | |
88 | ||
89 | WARN_ON(atomic_long_read(&buf->active_readers) != 1); | |
90 | if (SUBBUF_TRUNC(ltt_chanbuf_get_offset(buf), chan) | |
91 | - SUBBUF_TRUNC(ltt_chanbuf_get_consumed(buf), chan) | |
92 | == 0) { | |
93 | if (buf->finalized) | |
94 | return POLLHUP; | |
95 | else | |
96 | return 0; | |
97 | } else { | |
98 | if (SUBBUF_TRUNC(ltt_chanbuf_get_offset(buf), chan) | |
99 | - SUBBUF_TRUNC(ltt_chanbuf_get_consumed(buf), chan) | |
100 | >= chan->a.buf_size) | |
101 | return POLLPRI | POLLRDBAND; | |
102 | else | |
103 | return POLLIN | POLLRDNORM; | |
104 | } | |
105 | } | |
106 | return mask; | |
107 | } | |
108 | ||
109 | /** | |
110 | * ltt_ioctl - control on the debugfs file | |
111 | * | |
1c8284eb MD |
112 | * @filp: the file |
113 | * @cmd: the command | |
114 | * @arg: command arg | |
115 | * | |
116 | * This ioctl implements three commands necessary for a minimal | |
117 | * producer/consumer implementation : | |
118 | * RELAY_GET_SB | |
119 | * Get the next sub-buffer that can be read. It never blocks. | |
120 | * RELAY_PUT_SB | |
121 | * Release the currently read sub-buffer. Parameter is the last | |
122 | * put subbuffer (returned by GET_SUBBUF). | |
123 | * RELAY_GET_N_SB | |
124 | * returns the number of sub-buffers in the per cpu channel. | |
125 | * RELAY_GET_SB_SIZE | |
126 | * returns the size of the current sub-buffer. | |
127 | * RELAY_GET_MAX_SB_SIZE | |
128 | * returns the maximum size for sub-buffers. | |
129 | */ | |
130 | static | |
5050cf2d | 131 | long ltt_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
1c8284eb | 132 | { |
5050cf2d | 133 | struct inode *inode = filp->f_dentry->d_inode; |
1c8284eb MD |
134 | struct ltt_chanbuf *buf = inode->i_private; |
135 | u32 __user *argp = (u32 __user *)arg; | |
136 | ||
137 | switch (cmd) { | |
138 | case RELAY_GET_SB: | |
139 | { | |
140 | unsigned long consumed; | |
141 | int ret; | |
142 | ||
143 | ret = ltt_chanbuf_get_subbuf(buf, &consumed); | |
144 | if (ret) | |
145 | return ret; | |
146 | else | |
147 | return put_user((u32)consumed, argp); | |
148 | break; | |
149 | } | |
150 | case RELAY_PUT_SB: | |
151 | { | |
152 | u32 uconsumed_old; | |
153 | int ret; | |
154 | long consumed_old; | |
155 | ||
156 | ret = get_user(uconsumed_old, argp); | |
157 | if (ret) | |
158 | return ret; /* will return -EFAULT */ | |
159 | ||
160 | consumed_old = ltt_chanbuf_get_consumed(buf); | |
161 | consumed_old = consumed_old & (~0xFFFFFFFFL); | |
162 | consumed_old = consumed_old | uconsumed_old; | |
163 | ret = ltt_chanbuf_put_subbuf(buf, consumed_old); | |
164 | if (ret) | |
165 | return ret; | |
166 | break; | |
167 | } | |
168 | case RELAY_GET_N_SB: | |
169 | return put_user((u32)buf->a.chan->n_sb, argp); | |
170 | break; | |
171 | case RELAY_GET_SB_SIZE: | |
172 | return put_user(get_read_sb_size(buf), argp); | |
173 | break; | |
174 | case RELAY_GET_MAX_SB_SIZE: | |
175 | return put_user((u32)buf->a.chan->sb_size, argp); | |
176 | break; | |
177 | default: | |
178 | return -ENOIOCTLCMD; | |
179 | } | |
180 | return 0; | |
181 | } | |
182 | ||
183 | #ifdef CONFIG_COMPAT | |
184 | static | |
185 | long ltt_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |
186 | { | |
5050cf2d | 187 | return ltt_ioctl(file, cmd, arg); |
1c8284eb MD |
188 | } |
189 | #endif | |
190 | ||
191 | static const struct file_operations ltt_file_operations = { | |
192 | .open = ltt_open, | |
193 | .release = ltt_release, | |
194 | .poll = ltt_poll, | |
195 | .splice_read = ltt_relay_file_splice_read, | |
5050cf2d | 196 | .unlocked_ioctl = ltt_ioctl, |
1c8284eb MD |
197 | .llseek = ltt_relay_no_llseek, |
198 | #ifdef CONFIG_COMPAT | |
199 | .compat_ioctl = ltt_compat_ioctl, | |
200 | #endif | |
201 | }; | |
202 | ||
203 | int ltt_chanbuf_create_file(const char *filename, struct dentry *parent, | |
204 | int mode, struct ltt_chanbuf *buf) | |
205 | { | |
206 | struct ltt_chan *chan = container_of(buf->a.chan, struct ltt_chan, a); | |
207 | char *tmpname; | |
208 | int ret = 0; | |
209 | ||
210 | tmpname = kzalloc(NAME_MAX + 1, GFP_KERNEL); | |
211 | if (!tmpname) { | |
212 | ret = -ENOMEM; | |
213 | goto end; | |
214 | } | |
215 | ||
216 | snprintf(tmpname, NAME_MAX, "%s%s_%d", | |
217 | chan->overwrite ? LTT_FLIGHT_PREFIX : "", | |
218 | chan->a.filename, buf->a.cpu); | |
219 | ||
220 | buf->a.dentry = debugfs_create_file(tmpname, mode, parent, buf, | |
221 | <t_file_operations); | |
222 | if (!buf->a.dentry) { | |
223 | ret = -ENOMEM; | |
224 | goto free_name; | |
225 | } | |
226 | free_name: | |
227 | kfree(tmpname); | |
228 | end: | |
229 | return ret; | |
230 | } | |
231 | ||
232 | int ltt_chanbuf_remove_file(struct ltt_chanbuf *buf) | |
233 | { | |
234 | debugfs_remove(buf->a.dentry); | |
235 | ||
236 | return 0; | |
237 | } |