Fix: ring buffer: RING_BUFFER_FLUSH ioctl buffer corruption
[lttng-modules.git] / lib / ringbuffer / ring_buffer_vfs.c
1 /*
2 * ring_buffer_vfs.c
3 *
4 * Ring Buffer VFS file operations.
5 *
6 * Copyright (C) 2010-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; only
11 * version 2.1 of the License.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include <linux/module.h>
24 #include <linux/fs.h>
25 #include <linux/compat.h>
26
27 #include "../../wrapper/ringbuffer/backend.h"
28 #include "../../wrapper/ringbuffer/frontend.h"
29 #include "../../wrapper/ringbuffer/vfs.h"
30 #include "../../wrapper/poll.h"
31
32 static int put_ulong(unsigned long val, unsigned long arg)
33 {
34 return put_user(val, (unsigned long __user *)arg);
35 }
36
37 #ifdef CONFIG_COMPAT
38 static int compat_put_ulong(compat_ulong_t val, unsigned long arg)
39 {
40 return put_user(val, (compat_ulong_t __user *)compat_ptr(arg));
41 }
42 #endif
43
44 int lib_ring_buffer_open(struct inode *inode, struct file *file,
45 struct lib_ring_buffer *buf)
46 {
47 int ret;
48
49 if (!buf)
50 return -EINVAL;
51
52 ret = lib_ring_buffer_open_read(buf);
53 if (ret)
54 return ret;
55
56 ret = nonseekable_open(inode, file);
57 if (ret)
58 goto release_read;
59 return 0;
60
61 release_read:
62 lib_ring_buffer_release_read(buf);
63 return ret;
64 }
65 EXPORT_SYMBOL_GPL(lib_ring_buffer_open);
66
67 /**
68 * vfs_lib_ring_buffer_open - ring buffer open file operation
69 * @inode: opened inode
70 * @file: opened file
71 *
72 * Open implementation. Makes sure only one open instance of a buffer is
73 * done at a given moment.
74 */
75 static
76 int vfs_lib_ring_buffer_open(struct inode *inode, struct file *file)
77 {
78 struct lib_ring_buffer *buf = inode->i_private;
79
80 file->private_data = buf;
81 return lib_ring_buffer_open(inode, file, buf);
82 }
83
84 int lib_ring_buffer_release(struct inode *inode, struct file *file,
85 struct lib_ring_buffer *buf)
86 {
87 lib_ring_buffer_release_read(buf);
88
89 return 0;
90 }
91 EXPORT_SYMBOL_GPL(lib_ring_buffer_release);
92
93 /**
94 * vfs_lib_ring_buffer_release - ring buffer release file operation
95 * @inode: opened inode
96 * @file: opened file
97 *
98 * Release implementation.
99 */
100 static
101 int vfs_lib_ring_buffer_release(struct inode *inode, struct file *file)
102 {
103 struct lib_ring_buffer *buf = file->private_data;
104
105 return lib_ring_buffer_release(inode, file, buf);
106 }
107
108 unsigned int lib_ring_buffer_poll(struct file *filp, poll_table *wait,
109 struct lib_ring_buffer *buf)
110 {
111 unsigned int mask = 0;
112 struct channel *chan = buf->backend.chan;
113 const struct lib_ring_buffer_config *config = &chan->backend.config;
114 int finalized, disabled;
115
116 if (filp->f_mode & FMODE_READ) {
117 poll_wait_set_exclusive(wait);
118 poll_wait(filp, &buf->read_wait, wait);
119
120 finalized = lib_ring_buffer_is_finalized(config, buf);
121 disabled = lib_ring_buffer_channel_is_disabled(chan);
122
123 /*
124 * lib_ring_buffer_is_finalized() contains a smp_rmb() ordering
125 * finalized load before offsets loads.
126 */
127 WARN_ON(atomic_long_read(&buf->active_readers) != 1);
128 retry:
129 if (disabled)
130 return POLLERR;
131
132 if (subbuf_trunc(lib_ring_buffer_get_offset(config, buf), chan)
133 - subbuf_trunc(lib_ring_buffer_get_consumed(config, buf), chan)
134 == 0) {
135 if (finalized)
136 return POLLHUP;
137 else {
138 /*
139 * The memory barriers
140 * __wait_event()/wake_up_interruptible() take
141 * care of "raw_spin_is_locked" memory ordering.
142 */
143 if (raw_spin_is_locked(&buf->raw_tick_nohz_spinlock))
144 goto retry;
145 else
146 return 0;
147 }
148 } else {
149 if (subbuf_trunc(lib_ring_buffer_get_offset(config, buf),
150 chan)
151 - subbuf_trunc(lib_ring_buffer_get_consumed(config, buf),
152 chan)
153 >= chan->backend.buf_size)
154 return POLLPRI | POLLRDBAND;
155 else
156 return POLLIN | POLLRDNORM;
157 }
158 }
159 return mask;
160 }
161 EXPORT_SYMBOL_GPL(lib_ring_buffer_poll);
162
163 /**
164 * vfs_lib_ring_buffer_poll - ring buffer poll file operation
165 * @filp: the file
166 * @wait: poll table
167 *
168 * Poll implementation.
169 */
170 static
171 unsigned int vfs_lib_ring_buffer_poll(struct file *filp, poll_table *wait)
172 {
173 struct lib_ring_buffer *buf = filp->private_data;
174
175 return lib_ring_buffer_poll(filp, wait, buf);
176 }
177
178 long lib_ring_buffer_ioctl(struct file *filp, unsigned int cmd,
179 unsigned long arg, struct lib_ring_buffer *buf)
180 {
181 struct channel *chan = buf->backend.chan;
182 const struct lib_ring_buffer_config *config = &chan->backend.config;
183
184 if (lib_ring_buffer_channel_is_disabled(chan))
185 return -EIO;
186
187 switch (cmd) {
188 case RING_BUFFER_SNAPSHOT:
189 return lib_ring_buffer_snapshot(buf, &buf->cons_snapshot,
190 &buf->prod_snapshot);
191 case RING_BUFFER_SNAPSHOT_GET_CONSUMED:
192 return put_ulong(buf->cons_snapshot, arg);
193 case RING_BUFFER_SNAPSHOT_GET_PRODUCED:
194 return put_ulong(buf->prod_snapshot, arg);
195 case RING_BUFFER_GET_SUBBUF:
196 {
197 unsigned long uconsume;
198 long ret;
199
200 ret = get_user(uconsume, (unsigned long __user *) arg);
201 if (ret)
202 return ret; /* will return -EFAULT */
203 ret = lib_ring_buffer_get_subbuf(buf, uconsume);
204 if (!ret) {
205 /* Set file position to zero at each successful "get" */
206 filp->f_pos = 0;
207 }
208 return ret;
209 }
210 case RING_BUFFER_PUT_SUBBUF:
211 lib_ring_buffer_put_subbuf(buf);
212 return 0;
213
214 case RING_BUFFER_GET_NEXT_SUBBUF:
215 {
216 long ret;
217
218 ret = lib_ring_buffer_get_next_subbuf(buf);
219 if (!ret) {
220 /* Set file position to zero at each successful "get" */
221 filp->f_pos = 0;
222 }
223 return ret;
224 }
225 case RING_BUFFER_PUT_NEXT_SUBBUF:
226 lib_ring_buffer_put_next_subbuf(buf);
227 return 0;
228 case RING_BUFFER_GET_SUBBUF_SIZE:
229 return put_ulong(lib_ring_buffer_get_read_data_size(config, buf),
230 arg);
231 case RING_BUFFER_GET_PADDED_SUBBUF_SIZE:
232 {
233 unsigned long size;
234
235 size = lib_ring_buffer_get_read_data_size(config, buf);
236 size = PAGE_ALIGN(size);
237 return put_ulong(size, arg);
238 }
239 case RING_BUFFER_GET_MAX_SUBBUF_SIZE:
240 return put_ulong(chan->backend.subbuf_size, arg);
241 case RING_BUFFER_GET_MMAP_LEN:
242 {
243 unsigned long mmap_buf_len;
244
245 if (config->output != RING_BUFFER_MMAP)
246 return -EINVAL;
247 mmap_buf_len = chan->backend.buf_size;
248 if (chan->backend.extra_reader_sb)
249 mmap_buf_len += chan->backend.subbuf_size;
250 if (mmap_buf_len > INT_MAX)
251 return -EFBIG;
252 return put_ulong(mmap_buf_len, arg);
253 }
254 case RING_BUFFER_GET_MMAP_READ_OFFSET:
255 {
256 unsigned long sb_bindex;
257
258 if (config->output != RING_BUFFER_MMAP)
259 return -EINVAL;
260 sb_bindex = subbuffer_id_get_index(config,
261 buf->backend.buf_rsb.id);
262 return put_ulong(buf->backend.array[sb_bindex]->mmap_offset,
263 arg);
264 }
265 case RING_BUFFER_FLUSH:
266 lib_ring_buffer_switch_remote(buf);
267 return 0;
268 default:
269 return -ENOIOCTLCMD;
270 }
271 }
272 EXPORT_SYMBOL_GPL(lib_ring_buffer_ioctl);
273
274 /**
275 * vfs_lib_ring_buffer_ioctl - control ring buffer reader synchronization
276 *
277 * @filp: the file
278 * @cmd: the command
279 * @arg: command arg
280 *
281 * This ioctl implements commands necessary for producer/consumer
282 * and flight recorder reader interaction :
283 * RING_BUFFER_GET_NEXT_SUBBUF
284 * Get the next sub-buffer that can be read. It never blocks.
285 * RING_BUFFER_PUT_NEXT_SUBBUF
286 * Release the currently read sub-buffer.
287 * RING_BUFFER_GET_SUBBUF_SIZE
288 * returns the size of the current sub-buffer.
289 * RING_BUFFER_GET_MAX_SUBBUF_SIZE
290 * returns the maximum size for sub-buffers.
291 * RING_BUFFER_GET_NUM_SUBBUF
292 * returns the number of reader-visible sub-buffers in the per cpu
293 * channel (for mmap).
294 * RING_BUFFER_GET_MMAP_READ_OFFSET
295 * returns the offset of the subbuffer belonging to the reader.
296 * Should only be used for mmap clients.
297 */
298 static
299 long vfs_lib_ring_buffer_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
300 {
301 struct lib_ring_buffer *buf = filp->private_data;
302
303 return lib_ring_buffer_ioctl(filp, cmd, arg, buf);
304 }
305
306 #ifdef CONFIG_COMPAT
307 long lib_ring_buffer_compat_ioctl(struct file *filp, unsigned int cmd,
308 unsigned long arg, struct lib_ring_buffer *buf)
309 {
310 struct channel *chan = buf->backend.chan;
311 const struct lib_ring_buffer_config *config = &chan->backend.config;
312
313 if (lib_ring_buffer_channel_is_disabled(chan))
314 return -EIO;
315
316 switch (cmd) {
317 case RING_BUFFER_COMPAT_SNAPSHOT:
318 return lib_ring_buffer_snapshot(buf, &buf->cons_snapshot,
319 &buf->prod_snapshot);
320 case RING_BUFFER_COMPAT_SNAPSHOT_GET_CONSUMED:
321 return compat_put_ulong(buf->cons_snapshot, arg);
322 case RING_BUFFER_COMPAT_SNAPSHOT_GET_PRODUCED:
323 return compat_put_ulong(buf->prod_snapshot, arg);
324 case RING_BUFFER_COMPAT_GET_SUBBUF:
325 {
326 __u32 uconsume;
327 unsigned long consume;
328 long ret;
329
330 ret = get_user(uconsume, (__u32 __user *) arg);
331 if (ret)
332 return ret; /* will return -EFAULT */
333 consume = buf->cons_snapshot;
334 consume &= ~0xFFFFFFFFL;
335 consume |= uconsume;
336 ret = lib_ring_buffer_get_subbuf(buf, consume);
337 if (!ret) {
338 /* Set file position to zero at each successful "get" */
339 filp->f_pos = 0;
340 }
341 return ret;
342 }
343 case RING_BUFFER_COMPAT_PUT_SUBBUF:
344 lib_ring_buffer_put_subbuf(buf);
345 return 0;
346
347 case RING_BUFFER_COMPAT_GET_NEXT_SUBBUF:
348 {
349 long ret;
350
351 ret = lib_ring_buffer_get_next_subbuf(buf);
352 if (!ret) {
353 /* Set file position to zero at each successful "get" */
354 filp->f_pos = 0;
355 }
356 return ret;
357 }
358 case RING_BUFFER_COMPAT_PUT_NEXT_SUBBUF:
359 lib_ring_buffer_put_next_subbuf(buf);
360 return 0;
361 case RING_BUFFER_COMPAT_GET_SUBBUF_SIZE:
362 {
363 unsigned long data_size;
364
365 data_size = lib_ring_buffer_get_read_data_size(config, buf);
366 if (data_size > UINT_MAX)
367 return -EFBIG;
368 return compat_put_ulong(data_size, arg);
369 }
370 case RING_BUFFER_COMPAT_GET_PADDED_SUBBUF_SIZE:
371 {
372 unsigned long size;
373
374 size = lib_ring_buffer_get_read_data_size(config, buf);
375 size = PAGE_ALIGN(size);
376 if (size > UINT_MAX)
377 return -EFBIG;
378 return compat_put_ulong(size, arg);
379 }
380 case RING_BUFFER_COMPAT_GET_MAX_SUBBUF_SIZE:
381 if (chan->backend.subbuf_size > UINT_MAX)
382 return -EFBIG;
383 return compat_put_ulong(chan->backend.subbuf_size, arg);
384 case RING_BUFFER_COMPAT_GET_MMAP_LEN:
385 {
386 unsigned long mmap_buf_len;
387
388 if (config->output != RING_BUFFER_MMAP)
389 return -EINVAL;
390 mmap_buf_len = chan->backend.buf_size;
391 if (chan->backend.extra_reader_sb)
392 mmap_buf_len += chan->backend.subbuf_size;
393 if (mmap_buf_len > UINT_MAX)
394 return -EFBIG;
395 return compat_put_ulong(mmap_buf_len, arg);
396 }
397 case RING_BUFFER_COMPAT_GET_MMAP_READ_OFFSET:
398 {
399 unsigned long sb_bindex, read_offset;
400
401 if (config->output != RING_BUFFER_MMAP)
402 return -EINVAL;
403 sb_bindex = subbuffer_id_get_index(config,
404 buf->backend.buf_rsb.id);
405 read_offset = buf->backend.array[sb_bindex]->mmap_offset;
406 if (read_offset > UINT_MAX)
407 return -EINVAL;
408 return compat_put_ulong(read_offset, arg);
409 }
410 case RING_BUFFER_COMPAT_FLUSH:
411 lib_ring_buffer_switch_remote(buf);
412 return 0;
413 default:
414 return -ENOIOCTLCMD;
415 }
416 }
417 EXPORT_SYMBOL_GPL(lib_ring_buffer_compat_ioctl);
418
419 static
420 long vfs_lib_ring_buffer_compat_ioctl(struct file *filp, unsigned int cmd,
421 unsigned long arg)
422 {
423 struct lib_ring_buffer *buf = filp->private_data;
424
425 return lib_ring_buffer_compat_ioctl(filp, cmd, arg, buf);
426 }
427 #endif
428
429 const struct file_operations lib_ring_buffer_file_operations = {
430 .owner = THIS_MODULE,
431 .open = vfs_lib_ring_buffer_open,
432 .release = vfs_lib_ring_buffer_release,
433 .poll = vfs_lib_ring_buffer_poll,
434 .splice_read = vfs_lib_ring_buffer_splice_read,
435 .mmap = vfs_lib_ring_buffer_mmap,
436 .unlocked_ioctl = vfs_lib_ring_buffer_ioctl,
437 .llseek = vfs_lib_ring_buffer_no_llseek,
438 #ifdef CONFIG_COMPAT
439 .compat_ioctl = vfs_lib_ring_buffer_compat_ioctl,
440 #endif
441 };
442 EXPORT_SYMBOL_GPL(lib_ring_buffer_file_operations);
443
444 MODULE_LICENSE("GPL and additional rights");
445 MODULE_AUTHOR("Mathieu Desnoyers");
446 MODULE_DESCRIPTION("Ring Buffer Library VFS");
This page took 0.042759 seconds and 5 git commands to generate.