Blame view

drivers/oprofile/event_buffer.c 4.52 KB
1da177e4c   Linus Torvalds   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   Randy.Dunlap   [PATCH] move capa...
18
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
21
  #include <linux/dcookies.h>
  #include <linux/fs.h>
  #include <asm/uaccess.h>
6a18037d4   Robert Richter   oprofile: fixing ...
22

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
  #include "oprof.h"
  #include "event_buffer.h"
  #include "oprofile_stats.h"
59cc185ad   Markus Armbruster   [PATCH] oprofile:...
26
  DEFINE_MUTEX(buffer_mutex);
6a18037d4   Robert Richter   oprofile: fixing ...
27

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
  static unsigned long buffer_opened;
  static DECLARE_WAIT_QUEUE_HEAD(buffer_wait);
25ad2913c   Robert Richter   oprofile: more wh...
30
  static unsigned long *event_buffer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
33
  static unsigned long buffer_size;
  static unsigned long buffer_watershed;
  static size_t buffer_pos;
59cc185ad   Markus Armbruster   [PATCH] oprofile:...
34
  /* atomic_t because wait_event checks it outside of buffer_mutex */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
  static atomic_t buffer_ready = ATOMIC_INIT(0);
c0868934e   Robert Richter   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   Linus Torvalds   Linux-2.6.12-rc2
41
42
43
   */
  void add_event_entry(unsigned long value)
  {
066b3aa84   David Rientjes   oprofile: fix rac...
44
  	/*
c0868934e   Robert Richter   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   David Rientjes   oprofile: fix rac...
47
  	 */
c0868934e   Robert Richter   oprofile: warn on...
48
49
  	if (!event_buffer) {
  		WARN_ON_ONCE(1);
066b3aa84   David Rientjes   oprofile: fix rac...
50
  		return;
c0868934e   Robert Richter   oprofile: warn on...
51
  	}
066b3aa84   David Rientjes   oprofile: fix rac...
52

1da177e4c   Linus Torvalds   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   Markus Armbruster   [PATCH] oprofile:...
72
  	mutex_lock(&buffer_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
  	atomic_set(&buffer_ready, 1);
  	wake_up(&buffer_wait);
59cc185ad   Markus Armbruster   [PATCH] oprofile:...
75
  	mutex_unlock(&buffer_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
  }
6a18037d4   Robert Richter   oprofile: fixing ...
77

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
79
  int alloc_event_buffer(void)
  {
4dfc896e9   Jiri Kosina   [PATCH] oprofile:...
80
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81

2d21a29fb   Thomas Gleixner   locking, oprofile...
82
  	raw_spin_lock_irqsave(&oprofilefs_lock, flags);
bd2172f58   Robert Richter   oprofile: rename ...
83
84
  	buffer_size = oprofile_buffer_size;
  	buffer_watershed = oprofile_buffer_watershed;
2d21a29fb   Thomas Gleixner   locking, oprofile...
85
  	raw_spin_unlock_irqrestore(&oprofilefs_lock, flags);
6a18037d4   Robert Richter   oprofile: fixing ...
86

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
88
  	if (buffer_watershed >= buffer_size)
  		return -EINVAL;
6a18037d4   Robert Richter   oprofile: fixing ...
89

c0868934e   Robert Richter   oprofile: warn on...
90
  	buffer_pos = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
92
  	event_buffer = vmalloc(sizeof(unsigned long) * buffer_size);
  	if (!event_buffer)
c0868934e   Robert Richter   oprofile: warn on...
93
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94

c0868934e   Robert Richter   oprofile: warn on...
95
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
97
98
99
100
  }
  
  
  void free_event_buffer(void)
  {
066b3aa84   David Rientjes   oprofile: fix rac...
101
  	mutex_lock(&buffer_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
  	vfree(event_buffer);
c0868934e   Robert Richter   oprofile: warn on...
103
  	buffer_pos = 0;
f4156d1cd   Carl Love   powerpc/cell/opro...
104
  	event_buffer = NULL;
066b3aa84   David Rientjes   oprofile: fix rac...
105
  	mutex_unlock(&buffer_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
  }
6a18037d4   Robert Richter   oprofile: fixing ...
107

25ad2913c   Robert Richter   oprofile: more wh...
108
  static int event_buffer_open(struct inode *inode, struct file *file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
110
111
112
113
  {
  	int err = -EPERM;
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
cae042a73   Nick Piggin   oprofile: fix mem...
114
  	if (test_and_set_bit_lock(0, &buffer_opened))
1da177e4c   Linus Torvalds   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   Robert Richter   oprofile: fixing ...
125

1da177e4c   Linus Torvalds   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   Robert Richter   oprofile: fixing ...
132

729419f00   Arnd Bergmann   oprofile: make ev...
133
  	return nonseekable_open(inode, file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
135
136
137
  
  fail:
  	dcookie_unregister(file->private_data);
  out:
cae042a73   Nick Piggin   oprofile: fix mem...
138
  	__clear_bit_unlock(0, &buffer_opened);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
140
  	return err;
  }
25ad2913c   Robert Richter   oprofile: more wh...
141
  static int event_buffer_release(struct inode *inode, struct file *file)
1da177e4c   Linus Torvalds   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   Nick Piggin   oprofile: fix mem...
148
  	__clear_bit_unlock(0, &buffer_opened);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
150
  	return 0;
  }
25ad2913c   Robert Richter   oprofile: more wh...
151
152
  static ssize_t event_buffer_read(struct file *file, char __user *buf,
  				 size_t count, loff_t *offset)
1da177e4c   Linus Torvalds   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   Markus Armbruster   [PATCH] oprofile:...
169
  	mutex_lock(&buffer_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170

c0868934e   Robert Richter   oprofile: warn on...
171
  	/* May happen if the buffer is freed during pending reads. */
066b3aa84   David Rientjes   oprofile: fix rac...
172
173
174
175
  	if (!event_buffer) {
  		retval = -EINTR;
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
177
178
179
180
  	atomic_set(&buffer_ready, 0);
  
  	retval = -EFAULT;
  
  	count = buffer_pos * sizeof(unsigned long);
6a18037d4   Robert Richter   oprofile: fixing ...
181

1da177e4c   Linus Torvalds   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   Robert Richter   oprofile: fixing ...
187

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
  out:
59cc185ad   Markus Armbruster   [PATCH] oprofile:...
189
  	mutex_unlock(&buffer_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
191
  	return retval;
  }
6a18037d4   Robert Richter   oprofile: fixing ...
192

d54b1fdb1   Arjan van de Ven   [PATCH] mark stru...
193
  const struct file_operations event_buffer_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
195
196
  	.open		= event_buffer_open,
  	.release	= event_buffer_release,
  	.read		= event_buffer_read,
729419f00   Arnd Bergmann   oprofile: make ev...
197
  	.llseek		= no_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
  };