at v2.6.30 191 lines 4.1 kB view raw
1/** 2 * @file event_buffer.c 3 * 4 * @remark Copyright 2002 OProfile authors 5 * @remark Read the file COPYING 6 * 7 * @author John Levon <levon@movementarian.org> 8 * 9 * This is the global event buffer that the user-space 10 * daemon reads from. The event buffer is an untyped array 11 * of unsigned longs. Entries are prefixed by the 12 * escape value ESCAPE_CODE followed by an identifying code. 13 */ 14 15#include <linux/vmalloc.h> 16#include <linux/oprofile.h> 17#include <linux/sched.h> 18#include <linux/capability.h> 19#include <linux/dcookies.h> 20#include <linux/fs.h> 21#include <asm/uaccess.h> 22 23#include "oprof.h" 24#include "event_buffer.h" 25#include "oprofile_stats.h" 26 27DEFINE_MUTEX(buffer_mutex); 28 29static unsigned long buffer_opened; 30static DECLARE_WAIT_QUEUE_HEAD(buffer_wait); 31static unsigned long *event_buffer; 32static unsigned long buffer_size; 33static unsigned long buffer_watershed; 34static size_t buffer_pos; 35/* atomic_t because wait_event checks it outside of buffer_mutex */ 36static atomic_t buffer_ready = ATOMIC_INIT(0); 37 38/* Add an entry to the event buffer. When we 39 * get near to the end we wake up the process 40 * sleeping on the read() of the file. 41 */ 42void add_event_entry(unsigned long value) 43{ 44 if (buffer_pos == buffer_size) { 45 atomic_inc(&oprofile_stats.event_lost_overflow); 46 return; 47 } 48 49 event_buffer[buffer_pos] = value; 50 if (++buffer_pos == buffer_size - buffer_watershed) { 51 atomic_set(&buffer_ready, 1); 52 wake_up(&buffer_wait); 53 } 54} 55 56 57/* Wake up the waiting process if any. This happens 58 * on "echo 0 >/dev/oprofile/enable" so the daemon 59 * processes the data remaining in the event buffer. 60 */ 61void wake_up_buffer_waiter(void) 62{ 63 mutex_lock(&buffer_mutex); 64 atomic_set(&buffer_ready, 1); 65 wake_up(&buffer_wait); 66 mutex_unlock(&buffer_mutex); 67} 68 69 70int alloc_event_buffer(void) 71{ 72 int err = -ENOMEM; 73 unsigned long flags; 74 75 spin_lock_irqsave(&oprofilefs_lock, flags); 76 buffer_size = oprofile_buffer_size; 77 buffer_watershed = oprofile_buffer_watershed; 78 spin_unlock_irqrestore(&oprofilefs_lock, flags); 79 80 if (buffer_watershed >= buffer_size) 81 return -EINVAL; 82 83 event_buffer = vmalloc(sizeof(unsigned long) * buffer_size); 84 if (!event_buffer) 85 goto out; 86 87 err = 0; 88out: 89 return err; 90} 91 92 93void free_event_buffer(void) 94{ 95 vfree(event_buffer); 96 97 event_buffer = NULL; 98} 99 100 101static int event_buffer_open(struct inode *inode, struct file *file) 102{ 103 int err = -EPERM; 104 105 if (!capable(CAP_SYS_ADMIN)) 106 return -EPERM; 107 108 if (test_and_set_bit_lock(0, &buffer_opened)) 109 return -EBUSY; 110 111 /* Register as a user of dcookies 112 * to ensure they persist for the lifetime of 113 * the open event file 114 */ 115 err = -EINVAL; 116 file->private_data = dcookie_register(); 117 if (!file->private_data) 118 goto out; 119 120 if ((err = oprofile_setup())) 121 goto fail; 122 123 /* NB: the actual start happens from userspace 124 * echo 1 >/dev/oprofile/enable 125 */ 126 127 return 0; 128 129fail: 130 dcookie_unregister(file->private_data); 131out: 132 __clear_bit_unlock(0, &buffer_opened); 133 return err; 134} 135 136 137static int event_buffer_release(struct inode *inode, struct file *file) 138{ 139 oprofile_stop(); 140 oprofile_shutdown(); 141 dcookie_unregister(file->private_data); 142 buffer_pos = 0; 143 atomic_set(&buffer_ready, 0); 144 __clear_bit_unlock(0, &buffer_opened); 145 return 0; 146} 147 148 149static ssize_t event_buffer_read(struct file *file, char __user *buf, 150 size_t count, loff_t *offset) 151{ 152 int retval = -EINVAL; 153 size_t const max = buffer_size * sizeof(unsigned long); 154 155 /* handling partial reads is more trouble than it's worth */ 156 if (count != max || *offset) 157 return -EINVAL; 158 159 wait_event_interruptible(buffer_wait, atomic_read(&buffer_ready)); 160 161 if (signal_pending(current)) 162 return -EINTR; 163 164 /* can't currently happen */ 165 if (!atomic_read(&buffer_ready)) 166 return -EAGAIN; 167 168 mutex_lock(&buffer_mutex); 169 170 atomic_set(&buffer_ready, 0); 171 172 retval = -EFAULT; 173 174 count = buffer_pos * sizeof(unsigned long); 175 176 if (copy_to_user(buf, event_buffer, count)) 177 goto out; 178 179 retval = count; 180 buffer_pos = 0; 181 182out: 183 mutex_unlock(&buffer_mutex); 184 return retval; 185} 186 187const struct file_operations event_buffer_fops = { 188 .open = event_buffer_open, 189 .release = event_buffer_release, 190 .read = event_buffer_read, 191};