diff options
| author | Christopher Kenna <cjk@cs.unc.edu> | 2011-01-09 19:33:49 -0500 |
|---|---|---|
| committer | Bjoern B. Brandenburg <bbb@cs.unc.edu> | 2011-01-12 19:29:48 -0500 |
| commit | d11808b5c6b032de4284281ed2ff77ae697a4ebd (patch) | |
| tree | 0d135d237e96c3179b2983892b95bb9969a0166c | |
| parent | 37eb46be881dde4b405d3d8b48e76b4a8d62ae2c (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.
| -rw-r--r-- | include/litmus/ftdev.h | 10 | ||||
| -rw-r--r-- | litmus/ftdev.c | 131 | ||||
| -rw-r--r-- | litmus/sched_task_trace.c | 35 | ||||
| -rw-r--r-- | litmus/trace.c | 27 |
4 files changed, 148 insertions, 55 deletions
diff --git a/include/litmus/ftdev.h b/include/litmus/ftdev.h index efb2a5c9a9b0..348387e9adf9 100644 --- a/include/litmus/ftdev.h +++ b/include/litmus/ftdev.h | |||
| @@ -6,8 +6,6 @@ | |||
| 6 | #include <linux/mutex.h> | 6 | #include <linux/mutex.h> |
| 7 | #include <linux/cdev.h> | 7 | #include <linux/cdev.h> |
| 8 | 8 | ||
| 9 | #define MAX_FTDEV_MINORS NR_CPUS | ||
| 10 | |||
| 11 | #define FTDEV_ENABLE_CMD 0 | 9 | #define FTDEV_ENABLE_CMD 0 |
| 12 | #define FTDEV_DISABLE_CMD 1 | 10 | #define FTDEV_DISABLE_CMD 1 |
| 13 | 11 | ||
| @@ -32,11 +30,11 @@ struct ftdev_minor { | |||
| 32 | }; | 30 | }; |
| 33 | 31 | ||
| 34 | struct ftdev { | 32 | struct ftdev { |
| 33 | dev_t major; | ||
| 35 | struct cdev cdev; | 34 | struct cdev cdev; |
| 36 | struct class* class; | 35 | struct class* class; |
| 37 | const char* name; | 36 | const char* name; |
| 38 | /* FIXME: don't waste memory, allocate dynamically */ | 37 | struct ftdev_minor* minor; |
| 39 | struct ftdev_minor minor[MAX_FTDEV_MINORS]; | ||
| 40 | unsigned int minor_cnt; | 38 | unsigned int minor_cnt; |
| 41 | ftdev_alloc_t alloc; | 39 | ftdev_alloc_t alloc; |
| 42 | ftdev_free_t free; | 40 | ftdev_free_t free; |
| @@ -46,7 +44,9 @@ struct ftdev { | |||
| 46 | struct ft_buffer* alloc_ft_buffer(unsigned int count, size_t size); | 44 | struct ft_buffer* alloc_ft_buffer(unsigned int count, size_t size); |
| 47 | void free_ft_buffer(struct ft_buffer* buf); | 45 | void free_ft_buffer(struct ft_buffer* buf); |
| 48 | 46 | ||
| 49 | void ftdev_init(struct ftdev* ftdev, struct module* owner, const char* name); | 47 | int ftdev_init( struct ftdev* ftdev, struct module* owner, |
| 48 | const int minor_cnt, const char* name); | ||
| 49 | void ftdev_exit(struct ftdev* ftdev); | ||
| 50 | int register_ftdev(struct ftdev* ftdev); | 50 | int register_ftdev(struct ftdev* ftdev); |
| 51 | 51 | ||
| 52 | #endif | 52 | #endif |
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 | 313 | int ftdev_init( struct ftdev* ftdev, struct module* owner, | |
| 314 | void 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 | |||
| 355 | err_dealloc: | ||
| 356 | kfree(ftdev->minor); | ||
| 357 | err_out: | ||
| 358 | return err; | ||
| 359 | } | ||
| 360 | |||
| 361 | /* | ||
| 362 | * Destroy minor devices up to, but not including, up_to. | ||
| 363 | */ | ||
| 364 | static 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 | |||
| 375 | void 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 | ||
| 341 | int register_ftdev(struct ftdev* ftdev) | 385 | int 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 | } |
| 387 | out: | 430 | |
| 388 | return error; | 431 | return 0; |
| 432 | |||
| 433 | err_minors: | ||
| 434 | ftdev_device_destroy(ftdev, minor_cntr); | ||
| 435 | cdev_del(&ftdev->cdev); | ||
| 436 | err_unregister: | ||
| 437 | unregister_chrdev_region(MKDEV(ftdev->major, 0), ftdev->minor_cnt); | ||
| 438 | err_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) | |||
| 38 | static int __init init_sched_task_trace(void) | 38 | static 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 | |||
| 71 | err_dealloc: | ||
| 72 | ftdev_exit(&st_dev); | ||
| 73 | err_out: | ||
| 74 | printk(KERN_WARNING "Could not register sched_trace module\n"); | ||
| 75 | return err; | ||
| 76 | } | ||
| 77 | |||
| 78 | static void __exit exit_sched_task_trace(void) | ||
| 79 | { | ||
| 80 | ftdev_exit(&st_dev); | ||
| 61 | } | 81 | } |
| 62 | 82 | ||
| 63 | module_init(init_sched_task_trace); | 83 | module_init(init_sched_task_trace); |
| 84 | module_exit(exit_sched_task_trace); | ||
| 64 | 85 | ||
| 65 | 86 | ||
| 66 | static inline struct st_event_record* get_record(u8 type, struct task_struct* t) | 87 | static 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 | ||
| 91 | static int __init init_ft_overhead_trace(void) | 91 | static 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 | |||
| 109 | err_dealloc: | ||
| 110 | ftdev_exit(&overhead_dev); | ||
| 111 | err_out: | ||
| 112 | printk(KERN_WARNING "Could not register ft_trace module.\n"); | ||
| 113 | return err; | ||
| 114 | } | ||
| 115 | |||
| 116 | static void __exit exit_ft_overhead_trace(void) | ||
| 117 | { | ||
| 118 | ftdev_exit(&overhead_dev); | ||
| 99 | } | 119 | } |
| 100 | 120 | ||
| 101 | module_init(init_ft_overhead_trace); | 121 | module_init(init_ft_overhead_trace); |
| 122 | module_exit(exit_ft_overhead_trace); | ||
