aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--litmus/sched_trace.c184
1 files changed, 29 insertions, 155 deletions
diff --git a/litmus/sched_trace.c b/litmus/sched_trace.c
index 8051b51a2022..9b03e0cfe82b 100644
--- a/litmus/sched_trace.c
+++ b/litmus/sched_trace.c
@@ -2,7 +2,7 @@
2 * sched_trace.c -- record scheduling events to a byte stream. 2 * sched_trace.c -- record scheduling events to a byte stream.
3 */ 3 */
4#include <linux/spinlock.h> 4#include <linux/spinlock.h>
5#include <linux/semaphore.h> 5#include <linux/mutex.h>
6 6
7#include <linux/fs.h> 7#include <linux/fs.h>
8#include <linux/slab.h> 8#include <linux/slab.h>
@@ -19,7 +19,7 @@
19#define SCHED_TRACE_NAME "litmus/log" 19#define SCHED_TRACE_NAME "litmus/log"
20 20
21/* Allocate a buffer of about 32k per CPU */ 21/* Allocate a buffer of about 32k per CPU */
22#define LITMUS_TRACE_BUF_PAGES 8 22#define LITMUS_TRACE_BUF_PAGES 64
23#define LITMUS_TRACE_BUF_SIZE (PAGE_SIZE * LITMUS_TRACE_BUF_PAGES * NR_CPUS) 23#define LITMUS_TRACE_BUF_SIZE (PAGE_SIZE * LITMUS_TRACE_BUF_PAGES * NR_CPUS)
24 24
25/* Max length of one read from the buffer */ 25/* Max length of one read from the buffer */
@@ -28,123 +28,13 @@
28/* Max length for one write --- from kernel --- to the buffer */ 28/* Max length for one write --- from kernel --- to the buffer */
29#define MSG_SIZE 255 29#define MSG_SIZE 255
30 30
31/* Inner ring buffer structure */
32typedef struct {
33 rwlock_t del_lock;
34 31
35 /* the buffer */ 32static DEFINE_MUTEX(reader_mutex);
36 struct kfifo kfifo; 33static atomic_t reader_cnt = ATOMIC_INIT(0);
37} ring_buffer_t; 34static DEFINE_KFIFO(debug_buffer, char, LITMUS_TRACE_BUF_SIZE);
38 35
39/* Main buffer structure */
40typedef struct {
41 ring_buffer_t buf;
42 atomic_t reader_cnt;
43 struct semaphore reader_mutex;
44} trace_buffer_t;
45 36
46
47/*
48 * Inner buffer management functions
49 */
50void rb_init(ring_buffer_t* buf)
51{
52 rwlock_init(&buf->del_lock);
53}
54
55int rb_alloc_buf(ring_buffer_t* buf, unsigned int size)
56{
57 unsigned long flags;
58 int ret = 0;
59
60 write_lock_irqsave(&buf->del_lock, flags);
61
62 /* kfifo size must be a power of 2
63 * atm kfifo alloc is automatically rounding the size
64 */
65 ret = kfifo_alloc(&buf->kfifo, size, GFP_ATOMIC);
66
67 write_unlock_irqrestore(&buf->del_lock, flags);
68
69 if(ret < 0)
70 printk(KERN_ERR "kfifo_alloc failed\n");
71
72 return ret;
73}
74
75int rb_free_buf(ring_buffer_t* buf)
76{
77 unsigned long flags;
78
79 write_lock_irqsave(&buf->del_lock, flags);
80
81 BUG_ON(!kfifo_initialized(&buf->kfifo));
82 kfifo_free(&buf->kfifo);
83
84 write_unlock_irqrestore(&buf->del_lock, flags);
85
86 return 0;
87}
88
89/*
90 * Assumption: concurrent writes are serialized externally
91 *
92 * Will only succeed if there is enough space for all len bytes.
93 */
94int rb_put(ring_buffer_t* buf, char* mem, size_t len)
95{
96 unsigned long flags;
97 int error = 0;
98
99 read_lock_irqsave(&buf->del_lock, flags);
100
101 if (!kfifo_initialized(&buf->kfifo)) {
102 error = -ENODEV;
103 goto out;
104 }
105
106 if((kfifo_in(&buf->kfifo, mem, len)) < len) {
107 error = -ENOMEM;
108 goto out;
109 }
110
111 out:
112 read_unlock_irqrestore(&buf->del_lock, flags);
113 return error;
114}
115
116/* Assumption: concurrent reads are serialized externally */
117int rb_get(ring_buffer_t* buf, char* mem, size_t len)
118{
119 unsigned long flags;
120 int error = 0;
121
122 read_lock_irqsave(&buf->del_lock, flags);
123 if (!kfifo_initialized(&buf->kfifo)) {
124 error = -ENODEV;
125 goto out;
126 }
127
128 error = kfifo_out(&buf->kfifo, (unsigned char*)mem, len);
129
130 out:
131 read_unlock_irqrestore(&buf->del_lock, flags);
132 return error;
133}
134
135/*
136 * Device Driver management
137 */
138static DEFINE_RAW_SPINLOCK(log_buffer_lock); 37static DEFINE_RAW_SPINLOCK(log_buffer_lock);
139static trace_buffer_t log_buffer;
140
141static void init_log_buffer(void)
142{
143 rb_init(&log_buffer.buf);
144 atomic_set(&log_buffer.reader_cnt,0);
145 init_MUTEX(&log_buffer.reader_mutex);
146}
147
148static DEFINE_PER_CPU(char[MSG_SIZE], fmt_buffer); 38static DEFINE_PER_CPU(char[MSG_SIZE], fmt_buffer);
149 39
150/* 40/*
@@ -163,6 +53,10 @@ void sched_trace_log_message(const char* fmt, ...)
163 size_t len; 53 size_t len;
164 char* buf; 54 char* buf;
165 55
56 if (!atomic_read(&reader_cnt))
57 /* early exit if nobody is listening */
58 return;
59
166 va_start(args, fmt); 60 va_start(args, fmt);
167 local_irq_save(flags); 61 local_irq_save(flags);
168 62
@@ -171,32 +65,33 @@ void sched_trace_log_message(const char* fmt, ...)
171 len = vscnprintf(buf, MSG_SIZE, fmt, args); 65 len = vscnprintf(buf, MSG_SIZE, fmt, args);
172 66
173 raw_spin_lock(&log_buffer_lock); 67 raw_spin_lock(&log_buffer_lock);
174 /* Don't copy the trailing null byte, we don't want null bytes 68 /* Don't copy the trailing null byte, we don't want null bytes in a
175 * in a text file. 69 * text file.
176 */ 70 */
177 rb_put(&log_buffer.buf, buf, len); 71 kfifo_in(&debug_buffer, buf, len);
178 raw_spin_unlock(&log_buffer_lock); 72 raw_spin_unlock(&log_buffer_lock);
179 73
180 local_irq_restore(flags); 74 local_irq_restore(flags);
181 va_end(args); 75 va_end(args);
182} 76}
183 77
78
184/* 79/*
185 * log_read - Read the trace buffer 80 * log_read - Read the trace buffer
186 * 81 *
187 * This function is called as a file operation from userspace. 82 * This function is called as a file operation from userspace.
188 * Readers can sleep. Access is serialized through reader_mutex 83 * Readers can sleep. Access is serialized through reader_mutex
189 */ 84 */
190static ssize_t log_read(struct file *filp, char __user *to, size_t len, 85static ssize_t log_read(struct file *filp,
191 loff_t *f_pos) 86 char __user *to, size_t len,
87 loff_t *f_pos)
192{ 88{
193 /* we ignore f_pos, this is strictly sequential */ 89 /* we ignore f_pos, this is strictly sequential */
194 90
195 ssize_t error = -EINVAL; 91 ssize_t error = -EINVAL;
196 char* mem; 92 char* mem;
197 trace_buffer_t *tbuf = filp->private_data;
198 93
199 if (down_interruptible(&tbuf->reader_mutex)) { 94 if (mutex_lock_interruptible(&reader_mutex)) {
200 error = -ERESTARTSYS; 95 error = -ERESTARTSYS;
201 goto out; 96 goto out;
202 } 97 }
@@ -210,14 +105,14 @@ static ssize_t log_read(struct file *filp, char __user *to, size_t len,
210 goto out_unlock; 105 goto out_unlock;
211 } 106 }
212 107
213 error = rb_get(&tbuf->buf, mem, len); 108 error = kfifo_out(&debug_buffer, mem, len);
214 while (!error) { 109 while (!error) {
215 set_current_state(TASK_INTERRUPTIBLE); 110 set_current_state(TASK_INTERRUPTIBLE);
216 schedule_timeout(110); 111 schedule_timeout(110);
217 if (signal_pending(current)) 112 if (signal_pending(current))
218 error = -ERESTARTSYS; 113 error = -ERESTARTSYS;
219 else 114 else
220 error = rb_get(&tbuf->buf, mem, len); 115 error = kfifo_out(&debug_buffer, mem, len);
221 } 116 }
222 117
223 if (error > 0 && copy_to_user(to, mem, error)) 118 if (error > 0 && copy_to_user(to, mem, error))
@@ -225,7 +120,7 @@ static ssize_t log_read(struct file *filp, char __user *to, size_t len,
225 120
226 kfree(mem); 121 kfree(mem);
227 out_unlock: 122 out_unlock:
228 up(&tbuf->reader_mutex); 123 mutex_unlock(&reader_mutex);
229 out: 124 out:
230 return error; 125 return error;
231} 126}
@@ -243,36 +138,23 @@ extern int trace_recurse;
243static int log_open(struct inode *in, struct file *filp) 138static int log_open(struct inode *in, struct file *filp)
244{ 139{
245 int error = -EINVAL; 140 int error = -EINVAL;
246 trace_buffer_t* tbuf;
247
248 tbuf = &log_buffer;
249 141
250 if (down_interruptible(&tbuf->reader_mutex)) { 142 if (mutex_lock_interruptible(&reader_mutex)) {
251 error = -ERESTARTSYS; 143 error = -ERESTARTSYS;
252 goto out; 144 goto out;
253 } 145 }
254 146
255 /* first open must allocate buffers */ 147 atomic_inc(&reader_cnt);
256 if (atomic_inc_return(&tbuf->reader_cnt) == 1) {
257 if ((error = rb_alloc_buf(&tbuf->buf, LITMUS_TRACE_BUF_SIZE)))
258 {
259 atomic_dec(&tbuf->reader_cnt);
260 goto out_unlock;
261 }
262 }
263
264 error = 0; 148 error = 0;
265 filp->private_data = tbuf;
266 149
267 printk(KERN_DEBUG 150 printk(KERN_DEBUG
268 "sched_trace kfifo with buffer starting at: 0x%p\n", 151 "sched_trace kfifo with buffer starting at: 0x%p\n",
269 (tbuf->buf.kfifo).buf); 152 debug_buffer.buf);
270 153
271 /* override printk() */ 154 /* override printk() */
272 trace_override++; 155 trace_override++;
273 156
274 out_unlock: 157 mutex_unlock(&reader_mutex);
275 up(&tbuf->reader_mutex);
276 out: 158 out:
277 return error; 159 return error;
278} 160}
@@ -280,26 +162,20 @@ static int log_open(struct inode *in, struct file *filp)
280static int log_release(struct inode *in, struct file *filp) 162static int log_release(struct inode *in, struct file *filp)
281{ 163{
282 int error = -EINVAL; 164 int error = -EINVAL;
283 trace_buffer_t* tbuf = filp->private_data;
284
285 BUG_ON(!filp->private_data);
286 165
287 if (down_interruptible(&tbuf->reader_mutex)) { 166 if (mutex_lock_interruptible(&reader_mutex)) {
288 error = -ERESTARTSYS; 167 error = -ERESTARTSYS;
289 goto out; 168 goto out;
290 } 169 }
291 170
292 /* last release must deallocate buffers */ 171 atomic_dec(&reader_cnt);
293 if (atomic_dec_return(&tbuf->reader_cnt) == 0) {
294 error = rb_free_buf(&tbuf->buf);
295 }
296 172
297 /* release printk() overriding */ 173 /* release printk() overriding */
298 trace_override--; 174 trace_override--;
299 175
300 printk(KERN_DEBUG "sched_trace kfifo released\n"); 176 printk(KERN_DEBUG "sched_trace kfifo released\n");
301 177
302 up(&tbuf->reader_mutex); 178 mutex_unlock(&reader_mutex);
303 out: 179 out:
304 return error; 180 return error;
305} 181}
@@ -333,7 +209,7 @@ void dump_trace_buffer(int max)
333 /* potential, but very unlikely, race... */ 209 /* potential, but very unlikely, race... */
334 trace_recurse = 1; 210 trace_recurse = 1;
335 while ((max == 0 || count++ < max) && 211 while ((max == 0 || count++ < max) &&
336 (len = rb_get(&log_buffer.buf, line, sizeof(line) - 1)) > 0) { 212 (len = kfifo_out(&debug_buffer, line, sizeof(line - 1))) > 0) {
337 line[len] = '\0'; 213 line[len] = '\0';
338 printk("%s", line); 214 printk("%s", line);
339 } 215 }
@@ -355,7 +231,6 @@ static struct sysrq_key_op sysrq_dump_trace_buffer_op = {
355static int __init init_sched_trace(void) 231static int __init init_sched_trace(void)
356{ 232{
357 printk("Initializing TRACE() device\n"); 233 printk("Initializing TRACE() device\n");
358 init_log_buffer();
359 234
360#ifdef CONFIG_MAGIC_SYSRQ 235#ifdef CONFIG_MAGIC_SYSRQ
361 /* offer some debugging help */ 236 /* offer some debugging help */
@@ -365,7 +240,6 @@ static int __init init_sched_trace(void)
365 printk("Could not register dump-trace-buffer(Y) magic sysrq.\n"); 240 printk("Could not register dump-trace-buffer(Y) magic sysrq.\n");
366#endif 241#endif
367 242
368
369 return misc_register(&litmus_log_dev); 243 return misc_register(&litmus_log_dev);
370} 244}
371 245