Release 4.11 drivers/oprofile/event_buffer.c
/**
* @file event_buffer.c
*
* @remark Copyright 2002 OProfile authors
* @remark Read the file COPYING
*
* @author John Levon <levon@movementarian.org>
*
* This is the global event buffer that the user-space
* daemon reads from. The event buffer is an untyped array
* of unsigned longs. Entries are prefixed by the
* escape value ESCAPE_CODE followed by an identifying code.
*/
#include <linux/vmalloc.h>
#include <linux/oprofile.h>
#include <linux/sched/signal.h>
#include <linux/capability.h>
#include <linux/dcookies.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include "oprof.h"
#include "event_buffer.h"
#include "oprofile_stats.h"
DEFINE_MUTEX(buffer_mutex);
static unsigned long buffer_opened;
static DECLARE_WAIT_QUEUE_HEAD(buffer_wait);
static unsigned long *event_buffer;
static unsigned long buffer_size;
static unsigned long buffer_watershed;
static size_t buffer_pos;
/* atomic_t because wait_event checks it outside of buffer_mutex */
static atomic_t buffer_ready = ATOMIC_INIT(0);
/*
* Add an entry to the event buffer. When we get near to the end we
* wake up the process sleeping on the read() of the file. To protect
* the event_buffer this function may only be called when buffer_mutex
* is set.
*/
void add_event_entry(unsigned long value)
{
/*
* This shouldn't happen since all workqueues or handlers are
* canceled or flushed before the event buffer is freed.
*/
if (!event_buffer) {
WARN_ON_ONCE(1);
return;
}
if (buffer_pos == buffer_size) {
atomic_inc(&oprofile_stats.event_lost_overflow);
return;
}
event_buffer[buffer_pos] = value;
if (++buffer_pos == buffer_size - buffer_watershed) {
atomic_set(&buffer_ready, 1);
wake_up(&buffer_wait);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
John Levon | 58 | 80.56% | 1 | 33.33% |
Robert Richter | 8 | 11.11% | 1 | 33.33% |
David Rientjes | 6 | 8.33% | 1 | 33.33% |
Total | 72 | 100.00% | 3 | 100.00% |
/* Wake up the waiting process if any. This happens
* on "echo 0 >/dev/oprofile/enable" so the daemon
* processes the data remaining in the event buffer.
*/
void wake_up_buffer_waiter(void)
{
mutex_lock(&buffer_mutex);
atomic_set(&buffer_ready, 1);
wake_up(&buffer_wait);
mutex_unlock(&buffer_mutex);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
John Levon | 29 | 87.88% | 1 | 50.00% |
Markus Armbruster | 4 | 12.12% | 1 | 50.00% |
Total | 33 | 100.00% | 2 | 100.00% |
int alloc_event_buffer(void)
{
unsigned long flags;
raw_spin_lock_irqsave(&oprofilefs_lock, flags);
buffer_size = oprofile_buffer_size;
buffer_watershed = oprofile_buffer_watershed;
raw_spin_unlock_irqrestore(&oprofilefs_lock, flags);
if (buffer_watershed >= buffer_size)
return -EINVAL;
buffer_pos = 0;
event_buffer = vmalloc(sizeof(unsigned long) * buffer_size);
if (!event_buffer)
return -ENOMEM;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
John Levon | 53 | 71.62% | 1 | 20.00% |
Robert Richter | 11 | 14.86% | 2 | 40.00% |
Jiri Kosina | 8 | 10.81% | 1 | 20.00% |
Thomas Gleixner | 2 | 2.70% | 1 | 20.00% |
Total | 74 | 100.00% | 5 | 100.00% |
void free_event_buffer(void)
{
mutex_lock(&buffer_mutex);
vfree(event_buffer);
buffer_pos = 0;
event_buffer = NULL;
mutex_unlock(&buffer_mutex);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David Rientjes | 12 | 37.50% | 1 | 25.00% |
John Levon | 12 | 37.50% | 1 | 25.00% |
Carl E. Love | 4 | 12.50% | 1 | 25.00% |
Robert Richter | 4 | 12.50% | 1 | 25.00% |
Total | 32 | 100.00% | 4 | 100.00% |
static int event_buffer_open(struct inode *inode, struct file *file)
{
int err = -EPERM;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (test_and_set_bit_lock(0, &buffer_opened))
return -EBUSY;
/* Register as a user of dcookies
* to ensure they persist for the lifetime of
* the open event file
*/
err = -EINVAL;
file->private_data = dcookie_register();
if (!file->private_data)
goto out;
if ((err = oprofile_setup()))
goto fail;
/* NB: the actual start happens from userspace
* echo 1 >/dev/oprofile/enable
*/
return nonseekable_open(inode, file);
fail:
dcookie_unregister(file->private_data);
out:
__clear_bit_unlock(0, &buffer_opened);
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
John Levon | 105 | 92.11% | 1 | 25.00% |
Arnd Bergmann | 6 | 5.26% | 1 | 25.00% |
Nicholas Piggin | 2 | 1.75% | 1 | 25.00% |
Adrian Bunk | 1 | 0.88% | 1 | 25.00% |
Total | 114 | 100.00% | 4 | 100.00% |
static int event_buffer_release(struct inode *inode, struct file *file)
{
oprofile_stop();
oprofile_shutdown();
dcookie_unregister(file->private_data);
buffer_pos = 0;
atomic_set(&buffer_ready, 0);
__clear_bit_unlock(0, &buffer_opened);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
John Levon | 50 | 96.15% | 1 | 33.33% |
Nicholas Piggin | 1 | 1.92% | 1 | 33.33% |
Adrian Bunk | 1 | 1.92% | 1 | 33.33% |
Total | 52 | 100.00% | 3 | 100.00% |
static ssize_t event_buffer_read(struct file *file, char __user *buf,
size_t count, loff_t *offset)
{
int retval = -EINVAL;
size_t const max = buffer_size * sizeof(unsigned long);
/* handling partial reads is more trouble than it's worth */
if (count != max || *offset)
return -EINVAL;
wait_event_interruptible(buffer_wait, atomic_read(&buffer_ready));
if (signal_pending(current))
return -EINTR;
/* can't currently happen */
if (!atomic_read(&buffer_ready))
return -EAGAIN;
mutex_lock(&buffer_mutex);
/* May happen if the buffer is freed during pending reads. */
if (!event_buffer) {
retval = -EINTR;
goto out;
}
atomic_set(&buffer_ready, 0);
retval = -EFAULT;
count = buffer_pos * sizeof(unsigned long);
if (copy_to_user(buf, event_buffer, count))
goto out;
retval = count;
buffer_pos = 0;
out:
mutex_unlock(&buffer_mutex);
return retval;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
John Levon | 147 | 86.98% | 2 | 28.57% |
David Rientjes | 15 | 8.88% | 1 | 14.29% |
Markus Armbruster | 4 | 2.37% | 1 | 14.29% |
Robert Richter | 1 | 0.59% | 1 | 14.29% |
Al Viro | 1 | 0.59% | 1 | 14.29% |
Adrian Bunk | 1 | 0.59% | 1 | 14.29% |
Total | 169 | 100.00% | 7 | 100.00% |
const struct file_operations event_buffer_fops = {
.open = event_buffer_open,
.release = event_buffer_release,
.read = event_buffer_read,
.llseek = no_llseek,
};
Overall Contributors
Person | Tokens | Prop | Commits | CommitProp |
John Levon | 545 | 83.59% | 3 | 16.67% |
David Rientjes | 33 | 5.06% | 1 | 5.56% |
Robert Richter | 25 | 3.83% | 2 | 11.11% |
Markus Armbruster | 11 | 1.69% | 1 | 5.56% |
Arnd Bergmann | 11 | 1.69% | 1 | 5.56% |
Jiri Kosina | 8 | 1.23% | 1 | 5.56% |
Carl E. Love | 4 | 0.61% | 1 | 5.56% |
Adrian Bunk | 3 | 0.46% | 1 | 5.56% |
Nicholas Piggin | 3 | 0.46% | 1 | 5.56% |
Randy Dunlap | 3 | 0.46% | 1 | 5.56% |
Thomas Gleixner | 2 | 0.31% | 1 | 5.56% |
Al Viro | 1 | 0.15% | 1 | 5.56% |
Ingo Molnar | 1 | 0.15% | 1 | 5.56% |
Linus Torvalds | 1 | 0.15% | 1 | 5.56% |
Arjan van de Ven | 1 | 0.15% | 1 | 5.56% |
Total | 652 | 100.00% | 18 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.