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