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