aboutsummaryrefslogtreecommitdiffstats
path: root/litmus
diff options
context:
space:
mode:
authorChristopher Kenna <cjk@cs.unc.edu>2011-01-09 19:33:49 -0500
committerBjoern B. Brandenburg <bbb@cs.unc.edu>2011-01-12 19:29:48 -0500
commitd11808b5c6b032de4284281ed2ff77ae697a4ebd (patch)
tree0d135d237e96c3179b2983892b95bb9969a0166c /litmus
parent37eb46be881dde4b405d3d8b48e76b4a8d62ae2c (diff)
Feather-Trace: dynamic memory allocation and clean exit2011.1
This patch changes Feather-Trace to allocate memory for the minor devices dynamically, which addresses a long-standing FIXME. It also provides clean module exit and error conditions for Feather-Trace.
Diffstat (limited to 'litmus')
-rw-r--r--litmus/ftdev.c131
-rw-r--r--litmus/sched_task_trace.c35
-rw-r--r--litmus/trace.c27
3 files changed, 143 insertions, 50 deletions
diff --git a/litmus/ftdev.c b/litmus/ftdev.c
index d68d05c6d7dc..4a4b2e3e56c2 100644
--- a/litmus/ftdev.c
+++ b/litmus/ftdev.c
@@ -310,80 +310,131 @@ struct file_operations ftdev_fops = {
310 .read = ftdev_read, 310 .read = ftdev_read,
311}; 311};
312 312
313 313int ftdev_init( struct ftdev* ftdev, struct module* owner,
314void ftdev_init(struct ftdev* ftdev, struct module* owner, const char* name) 314 const int minor_cnt, const char* name)
315{ 315{
316 int i, error; 316 int i, err;
317
318 BUG_ON(minor_cnt < 1);
319
317 cdev_init(&ftdev->cdev, &ftdev_fops); 320 cdev_init(&ftdev->cdev, &ftdev_fops);
318 ftdev->name = name; 321 ftdev->name = name;
322 ftdev->minor_cnt = minor_cnt;
319 ftdev->cdev.owner = owner; 323 ftdev->cdev.owner = owner;
320 ftdev->cdev.ops = &ftdev_fops; 324 ftdev->cdev.ops = &ftdev_fops;
321 ftdev->minor_cnt = 0; 325 ftdev->alloc = NULL;
322 for (i = 0; i < MAX_FTDEV_MINORS; i++) { 326 ftdev->free = NULL;
327 ftdev->can_open = NULL;
328
329 ftdev->minor = kcalloc(ftdev->minor_cnt, sizeof(*ftdev->minor),
330 GFP_KERNEL);
331 if (!ftdev->minor) {
332 printk(KERN_WARNING "ftdev(%s): Could not allocate memory\n",
333 ftdev->name);
334 err = -ENOMEM;
335 goto err_out;
336 }
337
338 for (i = 0; i < ftdev->minor_cnt; i++) {
323 mutex_init(&ftdev->minor[i].lock); 339 mutex_init(&ftdev->minor[i].lock);
324 ftdev->minor[i].readers = 0; 340 ftdev->minor[i].readers = 0;
325 ftdev->minor[i].buf = NULL; 341 ftdev->minor[i].buf = NULL;
326 ftdev->minor[i].events = NULL; 342 ftdev->minor[i].events = NULL;
327 } 343 }
328 ftdev->alloc = NULL;
329 ftdev->free = NULL;
330 ftdev->can_open = NULL;
331 344
332 ftdev->class = class_create(owner, ftdev->name); 345 ftdev->class = class_create(owner, ftdev->name);
333 if (IS_ERR(ftdev->class)) { 346 if (IS_ERR(ftdev->class)) {
334 error = PTR_ERR(ftdev->class); 347 err = PTR_ERR(ftdev->class);
335 printk(KERN_WARNING "ftdev(%s): " 348 printk(KERN_WARNING "ftdev(%s): "
336 "Could not create device class.\n", 349 "Could not create device class.\n", ftdev->name);
337 name); 350 goto err_dealloc;
338 } 351 }
352
353 return 0;
354
355err_dealloc:
356 kfree(ftdev->minor);
357err_out:
358 return err;
359}
360
361/*
362 * Destroy minor devices up to, but not including, up_to.
363 */
364static void ftdev_device_destroy(struct ftdev* ftdev, unsigned int up_to)
365{
366 dev_t minor_cntr;
367
368 if (up_to < 1)
369 up_to = (ftdev->minor_cnt < 1) ? 0 : ftdev->minor_cnt;
370
371 for (minor_cntr = 0; minor_cntr < up_to; ++minor_cntr)
372 device_destroy(ftdev->class, MKDEV(ftdev->major, minor_cntr));
373}
374
375void ftdev_exit(struct ftdev* ftdev)
376{
377 printk("ftdev(%s): Exiting\n", ftdev->name);
378 ftdev_device_destroy(ftdev, -1);
379 cdev_del(&ftdev->cdev);
380 unregister_chrdev_region(MKDEV(ftdev->major, 0), ftdev->minor_cnt);
381 class_destroy(ftdev->class);
382 kfree(ftdev->minor);
339} 383}
340 384
341int register_ftdev(struct ftdev* ftdev) 385int register_ftdev(struct ftdev* ftdev)
342{ 386{
343 struct device **device; 387 struct device **device;
344 dev_t trace_dev; 388 dev_t trace_dev_tmp, minor_cntr;
345 int error = 0, major, i; 389 int err;
346 390
347 error = alloc_chrdev_region(&trace_dev, 0, ftdev->minor_cnt, 391 err = alloc_chrdev_region(&trace_dev_tmp, 0, ftdev->minor_cnt,
348 ftdev->name); 392 ftdev->name);
349 major = MAJOR(trace_dev); 393 if (err) {
350 if (error)
351 {
352 printk(KERN_WARNING "ftdev(%s): " 394 printk(KERN_WARNING "ftdev(%s): "
353 "Could not register major/minor number %d/%u\n", 395 "Could not allocate char. device region (%d minors)\n",
354 ftdev->name, major, ftdev->minor_cnt); 396 ftdev->name, ftdev->minor_cnt);
355 goto out; 397 goto err_out;
356 } 398 }
357 error = cdev_add(&ftdev->cdev, trace_dev, ftdev->minor_cnt); 399
358 if (error) { 400 ftdev->major = MAJOR(trace_dev_tmp);
401
402 err = cdev_add(&ftdev->cdev, trace_dev_tmp, ftdev->minor_cnt);
403 if (err) {
359 printk(KERN_WARNING "ftdev(%s): " 404 printk(KERN_WARNING "ftdev(%s): "
360 "Could not add cdev for major/minor = %d/%u.\n", 405 "Could not add cdev for major %u with %u minor(s).\n",
361 ftdev->name, major, ftdev->minor_cnt); 406 ftdev->name, ftdev->major, ftdev->minor_cnt);
362 goto out; 407 goto err_unregister;
363 } 408 }
364 409
365 /* 410 /* create the minor device(s) */
366 * create all the minor devices 411 for (minor_cntr = 0; minor_cntr < ftdev->minor_cnt; ++minor_cntr)
367 */
368 for (i = 0; i < ftdev->minor_cnt; ++i)
369 { 412 {
370 trace_dev = MKDEV(major, i); 413 trace_dev_tmp = MKDEV(ftdev->major, minor_cntr);
371 device = &(ftdev->minor[i].device); 414 device = &ftdev->minor[minor_cntr].device;
372 415
373 *device = device_create(ftdev->class, NULL, trace_dev, NULL, 416 *device = device_create(ftdev->class, NULL, trace_dev_tmp, NULL,
374 "%s%d", ftdev->name, i); 417 "litmus/%s%d", ftdev->name, minor_cntr);
375 if (IS_ERR(*device)) { 418 if (IS_ERR(*device)) {
376 error = PTR_ERR(*device); 419 err = PTR_ERR(*device);
377 printk(KERN_WARNING "ftdev(%s): " 420 printk(KERN_WARNING "ftdev(%s): "
378 "Could not create device major/minor number " 421 "Could not create device major/minor number "
379 "%d/%d\n", ftdev->name, major, i); 422 "%u/%u\n", ftdev->name, ftdev->major,
423 minor_cntr);
380 printk(KERN_WARNING "ftdev(%s): " 424 printk(KERN_WARNING "ftdev(%s): "
381 "Will not continue creating devices. Tracing " 425 "will attempt deletion of allocated devices.\n",
382 "may be in an inconsistent state.\n",
383 ftdev->name); 426 ftdev->name);
384 goto out; 427 goto err_minors;
385 } 428 }
386 } 429 }
387out: 430
388 return error; 431 return 0;
432
433err_minors:
434 ftdev_device_destroy(ftdev, minor_cntr);
435 cdev_del(&ftdev->cdev);
436err_unregister:
437 unregister_chrdev_region(MKDEV(ftdev->major, 0), ftdev->minor_cnt);
438err_out:
439 return err;
389} 440}
diff --git a/litmus/sched_task_trace.c b/litmus/sched_task_trace.c
index 7ef7b2889b42..a15b25d21a89 100644
--- a/litmus/sched_task_trace.c
+++ b/litmus/sched_task_trace.c
@@ -38,12 +38,17 @@ static int st_dev_can_open(struct ftdev *dev, unsigned int cpu)
38static int __init init_sched_task_trace(void) 38static int __init init_sched_task_trace(void)
39{ 39{
40 struct local_buffer* buf; 40 struct local_buffer* buf;
41 int i, ok = 0; 41 int i, ok = 0, err;
42 printk("Allocated %u sched_trace_xxx() events per CPU " 42 printk("Allocated %u sched_trace_xxx() events per CPU "
43 "(buffer size: %d bytes)\n", 43 "(buffer size: %d bytes)\n",
44 NO_EVENTS, (int) sizeof(struct local_buffer)); 44 NO_EVENTS, (int) sizeof(struct local_buffer));
45 ftdev_init(&st_dev, THIS_MODULE, "sched_trace"); 45
46 for (i = 0; i < NR_CPUS; i++) { 46 err = ftdev_init(&st_dev, THIS_MODULE,
47 num_online_cpus(), "sched_trace");
48 if (err)
49 goto err_out;
50
51 for (i = 0; i < st_dev.minor_cnt; i++) {
47 buf = &per_cpu(st_event_buffer, i); 52 buf = &per_cpu(st_event_buffer, i);
48 ok += init_ft_buffer(&buf->ftbuf, NO_EVENTS, 53 ok += init_ft_buffer(&buf->ftbuf, NO_EVENTS,
49 sizeof(struct st_event_record), 54 sizeof(struct st_event_record),
@@ -51,16 +56,32 @@ static int __init init_sched_task_trace(void)
51 buf->record); 56 buf->record);
52 st_dev.minor[i].buf = &buf->ftbuf; 57 st_dev.minor[i].buf = &buf->ftbuf;
53 } 58 }
54 if (ok == NR_CPUS) { 59 if (ok == st_dev.minor_cnt) {
55 st_dev.minor_cnt = NR_CPUS;
56 st_dev.can_open = st_dev_can_open; 60 st_dev.can_open = st_dev_can_open;
57 return register_ftdev(&st_dev); 61 err = register_ftdev(&st_dev);
62 if (err)
63 goto err_dealloc;
58 } else { 64 } else {
59 return -EINVAL; 65 err = -EINVAL;
66 goto err_dealloc;
60 } 67 }
68
69 return 0;
70
71err_dealloc:
72 ftdev_exit(&st_dev);
73err_out:
74 printk(KERN_WARNING "Could not register sched_trace module\n");
75 return err;
76}
77
78static void __exit exit_sched_task_trace(void)
79{
80 ftdev_exit(&st_dev);
61} 81}
62 82
63module_init(init_sched_task_trace); 83module_init(init_sched_task_trace);
84module_exit(exit_sched_task_trace);
64 85
65 86
66static inline struct st_event_record* get_record(u8 type, struct task_struct* t) 87static inline struct st_event_record* get_record(u8 type, struct task_struct* t)
diff --git a/litmus/trace.c b/litmus/trace.c
index da650dfe7f4d..e7ea1c2ab3e4 100644
--- a/litmus/trace.c
+++ b/litmus/trace.c
@@ -90,12 +90,33 @@ static void free_timestamp_buffer(struct ftdev* ftdev, unsigned int idx)
90 90
91static int __init init_ft_overhead_trace(void) 91static int __init init_ft_overhead_trace(void)
92{ 92{
93 int err;
94
93 printk("Initializing Feather-Trace overhead tracing device.\n"); 95 printk("Initializing Feather-Trace overhead tracing device.\n");
94 ftdev_init(&overhead_dev, THIS_MODULE, "ft_trace"); 96 err = ftdev_init(&overhead_dev, THIS_MODULE, 1, "ft_trace");
95 overhead_dev.minor_cnt = 1; /* only one buffer */ 97 if (err)
98 goto err_out;
99
96 overhead_dev.alloc = alloc_timestamp_buffer; 100 overhead_dev.alloc = alloc_timestamp_buffer;
97 overhead_dev.free = free_timestamp_buffer; 101 overhead_dev.free = free_timestamp_buffer;
98 return register_ftdev(&overhead_dev); 102
103 err = register_ftdev(&overhead_dev);
104 if (err)
105 goto err_dealloc;
106
107 return 0;
108
109err_dealloc:
110 ftdev_exit(&overhead_dev);
111err_out:
112 printk(KERN_WARNING "Could not register ft_trace module.\n");
113 return err;
114}
115
116static void __exit exit_ft_overhead_trace(void)
117{
118 ftdev_exit(&overhead_dev);
99} 119}
100 120
101module_init(init_ft_overhead_trace); 121module_init(init_ft_overhead_trace);
122module_exit(exit_ft_overhead_trace);