Cleanup: ring buffer: remove lib_ring_buffer_switch_new_end()
[lttng-modules.git] / lib / ringbuffer / ring_buffer_vfs.c
CommitLineData
f3bc08c5
MD
1/*
2 * ring_buffer_vfs.c
3 *
f3bc08c5
MD
4 * Ring Buffer VFS file operations.
5 *
886d51a3
MD
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
f3bc08c5
MD
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
32static 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
38static 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
d83004aa
JD
44int lib_ring_buffer_open(struct inode *inode, struct file *file,
45 struct lib_ring_buffer *buf)
f3bc08c5 46{
f3bc08c5
MD
47 int ret;
48
733ce41d
MD
49 if (!buf)
50 return -EINVAL;
51
f3bc08c5
MD
52 ret = lib_ring_buffer_open_read(buf);
53 if (ret)
54 return ret;
55
f3bc08c5
MD
56 ret = nonseekable_open(inode, file);
57 if (ret)
58 goto release_read;
59 return 0;
60
61release_read:
62 lib_ring_buffer_release_read(buf);
63 return ret;
64}
d83004aa 65EXPORT_SYMBOL_GPL(lib_ring_buffer_open);
f3bc08c5
MD
66
67/**
d83004aa 68 * vfs_lib_ring_buffer_open - ring buffer open file operation
f3bc08c5
MD
69 * @inode: opened inode
70 * @file: opened file
71 *
d83004aa
JD
72 * Open implementation. Makes sure only one open instance of a buffer is
73 * done at a given moment.
f3bc08c5 74 */
d83004aa
JD
75static
76int vfs_lib_ring_buffer_open(struct inode *inode, struct file *file)
f3bc08c5 77{
d83004aa
JD
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}
f3bc08c5 83
d83004aa
JD
84int lib_ring_buffer_release(struct inode *inode, struct file *file,
85 struct lib_ring_buffer *buf)
86{
f3bc08c5
MD
87 lib_ring_buffer_release_read(buf);
88
89 return 0;
90}
d83004aa 91EXPORT_SYMBOL_GPL(lib_ring_buffer_release);
f3bc08c5
MD
92
93/**
d83004aa
JD
94 * vfs_lib_ring_buffer_release - ring buffer release file operation
95 * @inode: opened inode
96 * @file: opened file
f3bc08c5 97 *
d83004aa 98 * Release implementation.
f3bc08c5 99 */
d83004aa
JD
100static
101int 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
108unsigned int lib_ring_buffer_poll(struct file *filp, poll_table *wait,
109 struct lib_ring_buffer *buf)
f3bc08c5
MD
110{
111 unsigned int mask = 0;
f3bc08c5 112 struct channel *chan = buf->backend.chan;
5a8fd222 113 const struct lib_ring_buffer_config *config = &chan->backend.config;
254ec7bc 114 int finalized, disabled;
f3bc08c5
MD
115
116 if (filp->f_mode & FMODE_READ) {
a33e44a6 117 poll_wait_set_exclusive(wait);
f3bc08c5
MD
118 poll_wait(filp, &buf->read_wait, wait);
119
120 finalized = lib_ring_buffer_is_finalized(config, buf);
254ec7bc
MD
121 disabled = lib_ring_buffer_channel_is_disabled(chan);
122
f3bc08c5
MD
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);
128retry:
254ec7bc
MD
129 if (disabled)
130 return POLLERR;
131
f3bc08c5
MD
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}
d83004aa 161EXPORT_SYMBOL_GPL(lib_ring_buffer_poll);
f3bc08c5
MD
162
163/**
d83004aa 164 * vfs_lib_ring_buffer_poll - ring buffer poll file operation
f3bc08c5 165 * @filp: the file
d83004aa 166 * @wait: poll table
f3bc08c5 167 *
d83004aa 168 * Poll implementation.
f3bc08c5 169 */
d83004aa
JD
170static
171unsigned int vfs_lib_ring_buffer_poll(struct file *filp, poll_table *wait)
f3bc08c5
MD
172{
173 struct lib_ring_buffer *buf = filp->private_data;
d83004aa
JD
174
175 return lib_ring_buffer_poll(filp, wait, buf);
176}
177
178long lib_ring_buffer_ioctl(struct file *filp, unsigned int cmd,
179 unsigned long arg, struct lib_ring_buffer *buf)
180{
f3bc08c5 181 struct channel *chan = buf->backend.chan;
5a8fd222 182 const struct lib_ring_buffer_config *config = &chan->backend.config;
f3bc08c5 183
254ec7bc
MD
184 if (lib_ring_buffer_channel_is_disabled(chan))
185 return -EIO;
186
f3bc08c5
MD
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 }
5c055266
MD
265 case RING_BUFFER_FLUSH:
266 lib_ring_buffer_switch_slow(buf, SWITCH_ACTIVE);
267 return 0;
f3bc08c5
MD
268 default:
269 return -ENOIOCTLCMD;
270 }
271}
d83004aa
JD
272EXPORT_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 */
298static
299long 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}
f3bc08c5
MD
305
306#ifdef CONFIG_COMPAT
307long lib_ring_buffer_compat_ioctl(struct file *filp, unsigned int cmd,
d83004aa 308 unsigned long arg, struct lib_ring_buffer *buf)
f3bc08c5 309{
f3bc08c5 310 struct channel *chan = buf->backend.chan;
5a8fd222 311 const struct lib_ring_buffer_config *config = &chan->backend.config;
254ec7bc
MD
312
313 if (lib_ring_buffer_channel_is_disabled(chan))
314 return -EIO;
f3bc08c5
MD
315
316 switch (cmd) {
216f7feb 317 case RING_BUFFER_COMPAT_SNAPSHOT:
f3bc08c5
MD
318 return lib_ring_buffer_snapshot(buf, &buf->cons_snapshot,
319 &buf->prod_snapshot);
216f7feb 320 case RING_BUFFER_COMPAT_SNAPSHOT_GET_CONSUMED:
f3bc08c5 321 return compat_put_ulong(buf->cons_snapshot, arg);
216f7feb 322 case RING_BUFFER_COMPAT_SNAPSHOT_GET_PRODUCED:
f3bc08c5 323 return compat_put_ulong(buf->prod_snapshot, arg);
216f7feb 324 case RING_BUFFER_COMPAT_GET_SUBBUF:
f3bc08c5
MD
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 }
216f7feb 343 case RING_BUFFER_COMPAT_PUT_SUBBUF:
f3bc08c5
MD
344 lib_ring_buffer_put_subbuf(buf);
345 return 0;
346
216f7feb 347 case RING_BUFFER_COMPAT_GET_NEXT_SUBBUF:
f3bc08c5
MD
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 }
216f7feb 358 case RING_BUFFER_COMPAT_PUT_NEXT_SUBBUF:
f3bc08c5
MD
359 lib_ring_buffer_put_next_subbuf(buf);
360 return 0;
216f7feb 361 case RING_BUFFER_COMPAT_GET_SUBBUF_SIZE:
f3bc08c5
MD
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;
4343ec8e 368 return compat_put_ulong(data_size, arg);
f3bc08c5 369 }
216f7feb 370 case RING_BUFFER_COMPAT_GET_PADDED_SUBBUF_SIZE:
f3bc08c5
MD
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;
4343ec8e 378 return compat_put_ulong(size, arg);
f3bc08c5 379 }
216f7feb 380 case RING_BUFFER_COMPAT_GET_MAX_SUBBUF_SIZE:
f3bc08c5
MD
381 if (chan->backend.subbuf_size > UINT_MAX)
382 return -EFBIG;
4343ec8e 383 return compat_put_ulong(chan->backend.subbuf_size, arg);
216f7feb 384 case RING_BUFFER_COMPAT_GET_MMAP_LEN:
f3bc08c5
MD
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;
4343ec8e 395 return compat_put_ulong(mmap_buf_len, arg);
f3bc08c5 396 }
216f7feb 397 case RING_BUFFER_COMPAT_GET_MMAP_READ_OFFSET:
f3bc08c5
MD
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;
4343ec8e 408 return compat_put_ulong(read_offset, arg);
f3bc08c5 409 }
216f7feb 410 case RING_BUFFER_COMPAT_FLUSH:
5c055266
MD
411 lib_ring_buffer_switch_slow(buf, SWITCH_ACTIVE);
412 return 0;
f3bc08c5
MD
413 default:
414 return -ENOIOCTLCMD;
415 }
416}
d83004aa
JD
417EXPORT_SYMBOL_GPL(lib_ring_buffer_compat_ioctl);
418
419static
420long 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}
f3bc08c5
MD
427#endif
428
429const struct file_operations lib_ring_buffer_file_operations = {
a33c9927 430 .owner = THIS_MODULE,
d83004aa
JD
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,
f3bc08c5 438#ifdef CONFIG_COMPAT
d83004aa 439 .compat_ioctl = vfs_lib_ring_buffer_compat_ioctl,
f3bc08c5
MD
440#endif
441};
442EXPORT_SYMBOL_GPL(lib_ring_buffer_file_operations);
443
444MODULE_LICENSE("GPL and additional rights");
445MODULE_AUTHOR("Mathieu Desnoyers");
446MODULE_DESCRIPTION("Ring Buffer Library VFS");
This page took 0.046794 seconds and 4 git commands to generate.