Blame view
drivers/oprofile/event_buffer.c
4.53 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/** * @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.h> |
c59ede7b7 [PATCH] move capa... |
18 |
#include <linux/capability.h> |
1da177e4c Linux-2.6.12-rc2 |
19 20 |
#include <linux/dcookies.h> #include <linux/fs.h> |
7c0f6ba68 Replace <asm/uacc... |
21 |
#include <linux/uaccess.h> |
6a18037d4 oprofile: fixing ... |
22 |
|
1da177e4c Linux-2.6.12-rc2 |
23 24 25 |
#include "oprof.h" #include "event_buffer.h" #include "oprofile_stats.h" |
59cc185ad [PATCH] oprofile:... |
26 |
DEFINE_MUTEX(buffer_mutex); |
6a18037d4 oprofile: fixing ... |
27 |
|
1da177e4c Linux-2.6.12-rc2 |
28 29 |
static unsigned long buffer_opened; static DECLARE_WAIT_QUEUE_HEAD(buffer_wait); |
25ad2913c oprofile: more wh... |
30 |
static unsigned long *event_buffer; |
1da177e4c Linux-2.6.12-rc2 |
31 32 33 |
static unsigned long buffer_size; static unsigned long buffer_watershed; static size_t buffer_pos; |
59cc185ad [PATCH] oprofile:... |
34 |
/* atomic_t because wait_event checks it outside of buffer_mutex */ |
1da177e4c Linux-2.6.12-rc2 |
35 |
static atomic_t buffer_ready = ATOMIC_INIT(0); |
c0868934e oprofile: warn on... |
36 37 38 39 40 |
/* * 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. |
1da177e4c Linux-2.6.12-rc2 |
41 42 43 |
*/ void add_event_entry(unsigned long value) { |
066b3aa84 oprofile: fix rac... |
44 |
/* |
c0868934e oprofile: warn on... |
45 46 |
* This shouldn't happen since all workqueues or handlers are * canceled or flushed before the event buffer is freed. |
066b3aa84 oprofile: fix rac... |
47 |
*/ |
c0868934e oprofile: warn on... |
48 49 |
if (!event_buffer) { WARN_ON_ONCE(1); |
066b3aa84 oprofile: fix rac... |
50 |
return; |
c0868934e oprofile: warn on... |
51 |
} |
066b3aa84 oprofile: fix rac... |
52 |
|
1da177e4c Linux-2.6.12-rc2 |
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
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); } } /* 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) { |
59cc185ad [PATCH] oprofile:... |
72 |
mutex_lock(&buffer_mutex); |
1da177e4c Linux-2.6.12-rc2 |
73 74 |
atomic_set(&buffer_ready, 1); wake_up(&buffer_wait); |
59cc185ad [PATCH] oprofile:... |
75 |
mutex_unlock(&buffer_mutex); |
1da177e4c Linux-2.6.12-rc2 |
76 |
} |
6a18037d4 oprofile: fixing ... |
77 |
|
1da177e4c Linux-2.6.12-rc2 |
78 79 |
int alloc_event_buffer(void) { |
4dfc896e9 [PATCH] oprofile:... |
80 |
unsigned long flags; |
1da177e4c Linux-2.6.12-rc2 |
81 |
|
2d21a29fb locking, oprofile... |
82 |
raw_spin_lock_irqsave(&oprofilefs_lock, flags); |
bd2172f58 oprofile: rename ... |
83 84 |
buffer_size = oprofile_buffer_size; buffer_watershed = oprofile_buffer_watershed; |
2d21a29fb locking, oprofile... |
85 |
raw_spin_unlock_irqrestore(&oprofilefs_lock, flags); |
6a18037d4 oprofile: fixing ... |
86 |
|
1da177e4c Linux-2.6.12-rc2 |
87 88 |
if (buffer_watershed >= buffer_size) return -EINVAL; |
6a18037d4 oprofile: fixing ... |
89 |
|
c0868934e oprofile: warn on... |
90 |
buffer_pos = 0; |
1da177e4c Linux-2.6.12-rc2 |
91 92 |
event_buffer = vmalloc(sizeof(unsigned long) * buffer_size); if (!event_buffer) |
c0868934e oprofile: warn on... |
93 |
return -ENOMEM; |
1da177e4c Linux-2.6.12-rc2 |
94 |
|
c0868934e oprofile: warn on... |
95 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
96 97 98 99 100 |
} void free_event_buffer(void) { |
066b3aa84 oprofile: fix rac... |
101 |
mutex_lock(&buffer_mutex); |
1da177e4c Linux-2.6.12-rc2 |
102 |
vfree(event_buffer); |
c0868934e oprofile: warn on... |
103 |
buffer_pos = 0; |
f4156d1cd powerpc/cell/opro... |
104 |
event_buffer = NULL; |
066b3aa84 oprofile: fix rac... |
105 |
mutex_unlock(&buffer_mutex); |
1da177e4c Linux-2.6.12-rc2 |
106 |
} |
6a18037d4 oprofile: fixing ... |
107 |
|
25ad2913c oprofile: more wh... |
108 |
static int event_buffer_open(struct inode *inode, struct file *file) |
1da177e4c Linux-2.6.12-rc2 |
109 110 111 112 113 |
{ int err = -EPERM; if (!capable(CAP_SYS_ADMIN)) return -EPERM; |
cae042a73 oprofile: fix mem... |
114 |
if (test_and_set_bit_lock(0, &buffer_opened)) |
1da177e4c Linux-2.6.12-rc2 |
115 116 117 118 119 120 121 122 123 124 |
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; |
6a18037d4 oprofile: fixing ... |
125 |
|
1da177e4c Linux-2.6.12-rc2 |
126 127 128 129 130 131 |
if ((err = oprofile_setup())) goto fail; /* NB: the actual start happens from userspace * echo 1 >/dev/oprofile/enable */ |
6a18037d4 oprofile: fixing ... |
132 |
|
729419f00 oprofile: make ev... |
133 |
return nonseekable_open(inode, file); |
1da177e4c Linux-2.6.12-rc2 |
134 135 136 137 |
fail: dcookie_unregister(file->private_data); out: |
cae042a73 oprofile: fix mem... |
138 |
__clear_bit_unlock(0, &buffer_opened); |
1da177e4c Linux-2.6.12-rc2 |
139 140 |
return err; } |
25ad2913c oprofile: more wh... |
141 |
static int event_buffer_release(struct inode *inode, struct file *file) |
1da177e4c Linux-2.6.12-rc2 |
142 143 144 145 146 147 |
{ oprofile_stop(); oprofile_shutdown(); dcookie_unregister(file->private_data); buffer_pos = 0; atomic_set(&buffer_ready, 0); |
cae042a73 oprofile: fix mem... |
148 |
__clear_bit_unlock(0, &buffer_opened); |
1da177e4c Linux-2.6.12-rc2 |
149 150 |
return 0; } |
25ad2913c oprofile: more wh... |
151 152 |
static ssize_t event_buffer_read(struct file *file, char __user *buf, size_t count, loff_t *offset) |
1da177e4c Linux-2.6.12-rc2 |
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
{ 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; |
59cc185ad [PATCH] oprofile:... |
169 |
mutex_lock(&buffer_mutex); |
1da177e4c Linux-2.6.12-rc2 |
170 |
|
c0868934e oprofile: warn on... |
171 |
/* May happen if the buffer is freed during pending reads. */ |
066b3aa84 oprofile: fix rac... |
172 173 174 175 |
if (!event_buffer) { retval = -EINTR; goto out; } |
1da177e4c Linux-2.6.12-rc2 |
176 177 178 179 180 |
atomic_set(&buffer_ready, 0); retval = -EFAULT; count = buffer_pos * sizeof(unsigned long); |
6a18037d4 oprofile: fixing ... |
181 |
|
1da177e4c Linux-2.6.12-rc2 |
182 183 184 185 186 |
if (copy_to_user(buf, event_buffer, count)) goto out; retval = count; buffer_pos = 0; |
6a18037d4 oprofile: fixing ... |
187 |
|
1da177e4c Linux-2.6.12-rc2 |
188 |
out: |
59cc185ad [PATCH] oprofile:... |
189 |
mutex_unlock(&buffer_mutex); |
1da177e4c Linux-2.6.12-rc2 |
190 191 |
return retval; } |
6a18037d4 oprofile: fixing ... |
192 |
|
d54b1fdb1 [PATCH] mark stru... |
193 |
const struct file_operations event_buffer_fops = { |
1da177e4c Linux-2.6.12-rc2 |
194 195 196 |
.open = event_buffer_open, .release = event_buffer_release, .read = event_buffer_read, |
729419f00 oprofile: make ev... |
197 |
.llseek = no_llseek, |
1da177e4c Linux-2.6.12-rc2 |
198 |
}; |