diff options
Diffstat (limited to 'kernel/relay.c')
-rw-r--r-- | kernel/relay.c | 192 |
1 files changed, 133 insertions, 59 deletions
diff --git a/kernel/relay.c b/kernel/relay.c index 284e2e8b4eed..ef8a935710a2 100644 --- a/kernel/relay.c +++ b/kernel/relay.c | |||
@@ -7,6 +7,8 @@ | |||
7 | * Copyright (C) 1999-2005 - Karim Yaghmour (karim@opersys.com) | 7 | * Copyright (C) 1999-2005 - Karim Yaghmour (karim@opersys.com) |
8 | * | 8 | * |
9 | * Moved to kernel/relay.c by Paul Mundt, 2006. | 9 | * Moved to kernel/relay.c by Paul Mundt, 2006. |
10 | * November 2006 - CPU hotplug support by Mathieu Desnoyers | ||
11 | * (mathieu.desnoyers@polymtl.ca) | ||
10 | * | 12 | * |
11 | * This file is released under the GPL. | 13 | * This file is released under the GPL. |
12 | */ | 14 | */ |
@@ -18,6 +20,11 @@ | |||
18 | #include <linux/relay.h> | 20 | #include <linux/relay.h> |
19 | #include <linux/vmalloc.h> | 21 | #include <linux/vmalloc.h> |
20 | #include <linux/mm.h> | 22 | #include <linux/mm.h> |
23 | #include <linux/cpu.h> | ||
24 | |||
25 | /* list of open channels, for cpu hotplug */ | ||
26 | static DEFINE_MUTEX(relay_channels_mutex); | ||
27 | static LIST_HEAD(relay_channels); | ||
21 | 28 | ||
22 | /* | 29 | /* |
23 | * close() vm_op implementation for relay file mapping. | 30 | * close() vm_op implementation for relay file mapping. |
@@ -187,6 +194,7 @@ void relay_destroy_buf(struct rchan_buf *buf) | |||
187 | __free_page(buf->page_array[i]); | 194 | __free_page(buf->page_array[i]); |
188 | kfree(buf->page_array); | 195 | kfree(buf->page_array); |
189 | } | 196 | } |
197 | chan->buf[buf->cpu] = NULL; | ||
190 | kfree(buf->padding); | 198 | kfree(buf->padding); |
191 | kfree(buf); | 199 | kfree(buf); |
192 | kref_put(&chan->kref, relay_destroy_channel); | 200 | kref_put(&chan->kref, relay_destroy_channel); |
@@ -320,7 +328,7 @@ static void wakeup_readers(struct work_struct *work) | |||
320 | * @buf: the channel buffer | 328 | * @buf: the channel buffer |
321 | * @init: 1 if this is a first-time initialization | 329 | * @init: 1 if this is a first-time initialization |
322 | * | 330 | * |
323 | * See relay_reset for description of effect. | 331 | * See relay_reset() for description of effect. |
324 | */ | 332 | */ |
325 | static void __relay_reset(struct rchan_buf *buf, unsigned int init) | 333 | static void __relay_reset(struct rchan_buf *buf, unsigned int init) |
326 | { | 334 | { |
@@ -356,57 +364,75 @@ static void __relay_reset(struct rchan_buf *buf, unsigned int init) | |||
356 | * and restarting the channel in its initial state. The buffers | 364 | * and restarting the channel in its initial state. The buffers |
357 | * are not freed, so any mappings are still in effect. | 365 | * are not freed, so any mappings are still in effect. |
358 | * | 366 | * |
359 | * NOTE: Care should be taken that the channel isn't actually | 367 | * NOTE. Care should be taken that the channel isn't actually |
360 | * being used by anything when this call is made. | 368 | * being used by anything when this call is made. |
361 | */ | 369 | */ |
362 | void relay_reset(struct rchan *chan) | 370 | void relay_reset(struct rchan *chan) |
363 | { | 371 | { |
364 | unsigned int i; | 372 | unsigned int i; |
365 | struct rchan_buf *prev = NULL; | ||
366 | 373 | ||
367 | if (!chan) | 374 | if (!chan) |
368 | return; | 375 | return; |
369 | 376 | ||
370 | for (i = 0; i < NR_CPUS; i++) { | 377 | if (chan->is_global && chan->buf[0]) { |
371 | if (!chan->buf[i] || chan->buf[i] == prev) | 378 | __relay_reset(chan->buf[0], 0); |
372 | break; | 379 | return; |
373 | __relay_reset(chan->buf[i], 0); | ||
374 | prev = chan->buf[i]; | ||
375 | } | 380 | } |
381 | |||
382 | mutex_lock(&relay_channels_mutex); | ||
383 | for_each_online_cpu(i) | ||
384 | if (chan->buf[i]) | ||
385 | __relay_reset(chan->buf[i], 0); | ||
386 | mutex_unlock(&relay_channels_mutex); | ||
376 | } | 387 | } |
377 | EXPORT_SYMBOL_GPL(relay_reset); | 388 | EXPORT_SYMBOL_GPL(relay_reset); |
378 | 389 | ||
379 | /* | 390 | /* |
380 | * relay_open_buf - create a new relay channel buffer | 391 | * relay_open_buf - create a new relay channel buffer |
381 | * | 392 | * |
382 | * Internal - used by relay_open(). | 393 | * used by relay_open() and CPU hotplug. |
383 | */ | 394 | */ |
384 | static struct rchan_buf *relay_open_buf(struct rchan *chan, | 395 | static struct rchan_buf *relay_open_buf(struct rchan *chan, unsigned int cpu) |
385 | const char *filename, | ||
386 | struct dentry *parent, | ||
387 | int *is_global) | ||
388 | { | 396 | { |
389 | struct rchan_buf *buf; | 397 | struct rchan_buf *buf = NULL; |
390 | struct dentry *dentry; | 398 | struct dentry *dentry; |
399 | char *tmpname; | ||
391 | 400 | ||
392 | if (*is_global) | 401 | if (chan->is_global) |
393 | return chan->buf[0]; | 402 | return chan->buf[0]; |
394 | 403 | ||
404 | tmpname = kzalloc(NAME_MAX + 1, GFP_KERNEL); | ||
405 | if (!tmpname) | ||
406 | goto end; | ||
407 | snprintf(tmpname, NAME_MAX, "%s%d", chan->base_filename, cpu); | ||
408 | |||
395 | buf = relay_create_buf(chan); | 409 | buf = relay_create_buf(chan); |
396 | if (!buf) | 410 | if (!buf) |
397 | return NULL; | 411 | goto free_name; |
412 | |||
413 | buf->cpu = cpu; | ||
414 | __relay_reset(buf, 1); | ||
398 | 415 | ||
399 | /* Create file in fs */ | 416 | /* Create file in fs */ |
400 | dentry = chan->cb->create_buf_file(filename, parent, S_IRUSR, | 417 | dentry = chan->cb->create_buf_file(tmpname, chan->parent, S_IRUSR, |
401 | buf, is_global); | 418 | buf, &chan->is_global); |
402 | if (!dentry) { | 419 | if (!dentry) |
403 | relay_destroy_buf(buf); | 420 | goto free_buf; |
404 | return NULL; | ||
405 | } | ||
406 | 421 | ||
407 | buf->dentry = dentry; | 422 | buf->dentry = dentry; |
408 | __relay_reset(buf, 1); | ||
409 | 423 | ||
424 | if(chan->is_global) { | ||
425 | chan->buf[0] = buf; | ||
426 | buf->cpu = 0; | ||
427 | } | ||
428 | |||
429 | goto free_name; | ||
430 | |||
431 | free_buf: | ||
432 | relay_destroy_buf(buf); | ||
433 | free_name: | ||
434 | kfree(tmpname); | ||
435 | end: | ||
410 | return buf; | 436 | return buf; |
411 | } | 437 | } |
412 | 438 | ||
@@ -448,31 +474,71 @@ static void setup_callbacks(struct rchan *chan, | |||
448 | } | 474 | } |
449 | 475 | ||
450 | /** | 476 | /** |
477 | * | ||
478 | * relay_hotcpu_callback - CPU hotplug callback | ||
479 | * @nb: notifier block | ||
480 | * @action: hotplug action to take | ||
481 | * @hcpu: CPU number | ||
482 | * | ||
483 | * Returns the success/failure of the operation. (NOTIFY_OK, NOTIFY_BAD) | ||
484 | */ | ||
485 | static int __cpuinit relay_hotcpu_callback(struct notifier_block *nb, | ||
486 | unsigned long action, | ||
487 | void *hcpu) | ||
488 | { | ||
489 | unsigned int hotcpu = (unsigned long)hcpu; | ||
490 | struct rchan *chan; | ||
491 | |||
492 | switch(action) { | ||
493 | case CPU_UP_PREPARE: | ||
494 | mutex_lock(&relay_channels_mutex); | ||
495 | list_for_each_entry(chan, &relay_channels, list) { | ||
496 | if (chan->buf[hotcpu]) | ||
497 | continue; | ||
498 | chan->buf[hotcpu] = relay_open_buf(chan, hotcpu); | ||
499 | if(!chan->buf[hotcpu]) { | ||
500 | printk(KERN_ERR | ||
501 | "relay_hotcpu_callback: cpu %d buffer " | ||
502 | "creation failed\n", hotcpu); | ||
503 | mutex_unlock(&relay_channels_mutex); | ||
504 | return NOTIFY_BAD; | ||
505 | } | ||
506 | } | ||
507 | mutex_unlock(&relay_channels_mutex); | ||
508 | break; | ||
509 | case CPU_DEAD: | ||
510 | /* No need to flush the cpu : will be flushed upon | ||
511 | * final relay_flush() call. */ | ||
512 | break; | ||
513 | } | ||
514 | return NOTIFY_OK; | ||
515 | } | ||
516 | |||
517 | /** | ||
451 | * relay_open - create a new relay channel | 518 | * relay_open - create a new relay channel |
452 | * @base_filename: base name of files to create | 519 | * @base_filename: base name of files to create |
453 | * @parent: dentry of parent directory, %NULL for root directory | 520 | * @parent: dentry of parent directory, %NULL for root directory |
454 | * @subbuf_size: size of sub-buffers | 521 | * @subbuf_size: size of sub-buffers |
455 | * @n_subbufs: number of sub-buffers | 522 | * @n_subbufs: number of sub-buffers |
456 | * @cb: client callback functions | 523 | * @cb: client callback functions |
524 | * @private_data: user-defined data | ||
457 | * | 525 | * |
458 | * Returns channel pointer if successful, %NULL otherwise. | 526 | * Returns channel pointer if successful, %NULL otherwise. |
459 | * | 527 | * |
460 | * Creates a channel buffer for each cpu using the sizes and | 528 | * Creates a channel buffer for each cpu using the sizes and |
461 | * attributes specified. The created channel buffer files | 529 | * attributes specified. The created channel buffer files |
462 | * will be named base_filename0...base_filenameN-1. File | 530 | * will be named base_filename0...base_filenameN-1. File |
463 | * permissions will be S_IRUSR. | 531 | * permissions will be %S_IRUSR. |
464 | */ | 532 | */ |
465 | struct rchan *relay_open(const char *base_filename, | 533 | struct rchan *relay_open(const char *base_filename, |
466 | struct dentry *parent, | 534 | struct dentry *parent, |
467 | size_t subbuf_size, | 535 | size_t subbuf_size, |
468 | size_t n_subbufs, | 536 | size_t n_subbufs, |
469 | struct rchan_callbacks *cb) | 537 | struct rchan_callbacks *cb, |
538 | void *private_data) | ||
470 | { | 539 | { |
471 | unsigned int i; | 540 | unsigned int i; |
472 | struct rchan *chan; | 541 | struct rchan *chan; |
473 | char *tmpname; | ||
474 | int is_global = 0; | ||
475 | |||
476 | if (!base_filename) | 542 | if (!base_filename) |
477 | return NULL; | 543 | return NULL; |
478 | 544 | ||
@@ -487,38 +553,32 @@ struct rchan *relay_open(const char *base_filename, | |||
487 | chan->n_subbufs = n_subbufs; | 553 | chan->n_subbufs = n_subbufs; |
488 | chan->subbuf_size = subbuf_size; | 554 | chan->subbuf_size = subbuf_size; |
489 | chan->alloc_size = FIX_SIZE(subbuf_size * n_subbufs); | 555 | chan->alloc_size = FIX_SIZE(subbuf_size * n_subbufs); |
556 | chan->parent = parent; | ||
557 | chan->private_data = private_data; | ||
558 | strlcpy(chan->base_filename, base_filename, NAME_MAX); | ||
490 | setup_callbacks(chan, cb); | 559 | setup_callbacks(chan, cb); |
491 | kref_init(&chan->kref); | 560 | kref_init(&chan->kref); |
492 | 561 | ||
493 | tmpname = kmalloc(NAME_MAX + 1, GFP_KERNEL); | 562 | mutex_lock(&relay_channels_mutex); |
494 | if (!tmpname) | ||
495 | goto free_chan; | ||
496 | |||
497 | for_each_online_cpu(i) { | 563 | for_each_online_cpu(i) { |
498 | sprintf(tmpname, "%s%d", base_filename, i); | 564 | chan->buf[i] = relay_open_buf(chan, i); |
499 | chan->buf[i] = relay_open_buf(chan, tmpname, parent, | ||
500 | &is_global); | ||
501 | if (!chan->buf[i]) | 565 | if (!chan->buf[i]) |
502 | goto free_bufs; | 566 | goto free_bufs; |
503 | |||
504 | chan->buf[i]->cpu = i; | ||
505 | } | 567 | } |
568 | list_add(&chan->list, &relay_channels); | ||
569 | mutex_unlock(&relay_channels_mutex); | ||
506 | 570 | ||
507 | kfree(tmpname); | ||
508 | return chan; | 571 | return chan; |
509 | 572 | ||
510 | free_bufs: | 573 | free_bufs: |
511 | for (i = 0; i < NR_CPUS; i++) { | 574 | for_each_online_cpu(i) { |
512 | if (!chan->buf[i]) | 575 | if (!chan->buf[i]) |
513 | break; | 576 | break; |
514 | relay_close_buf(chan->buf[i]); | 577 | relay_close_buf(chan->buf[i]); |
515 | if (is_global) | ||
516 | break; | ||
517 | } | 578 | } |
518 | kfree(tmpname); | ||
519 | 579 | ||
520 | free_chan: | ||
521 | kref_put(&chan->kref, relay_destroy_channel); | 580 | kref_put(&chan->kref, relay_destroy_channel); |
581 | mutex_unlock(&relay_channels_mutex); | ||
522 | return NULL; | 582 | return NULL; |
523 | } | 583 | } |
524 | EXPORT_SYMBOL_GPL(relay_open); | 584 | EXPORT_SYMBOL_GPL(relay_open); |
@@ -588,7 +648,7 @@ EXPORT_SYMBOL_GPL(relay_switch_subbuf); | |||
588 | * subbufs_consumed should be the number of sub-buffers newly consumed, | 648 | * subbufs_consumed should be the number of sub-buffers newly consumed, |
589 | * not the total consumed. | 649 | * not the total consumed. |
590 | * | 650 | * |
591 | * NOTE: Kernel clients don't need to call this function if the channel | 651 | * NOTE. Kernel clients don't need to call this function if the channel |
592 | * mode is 'overwrite'. | 652 | * mode is 'overwrite'. |
593 | */ | 653 | */ |
594 | void relay_subbufs_consumed(struct rchan *chan, | 654 | void relay_subbufs_consumed(struct rchan *chan, |
@@ -619,24 +679,26 @@ EXPORT_SYMBOL_GPL(relay_subbufs_consumed); | |||
619 | void relay_close(struct rchan *chan) | 679 | void relay_close(struct rchan *chan) |
620 | { | 680 | { |
621 | unsigned int i; | 681 | unsigned int i; |
622 | struct rchan_buf *prev = NULL; | ||
623 | 682 | ||
624 | if (!chan) | 683 | if (!chan) |
625 | return; | 684 | return; |
626 | 685 | ||
627 | for (i = 0; i < NR_CPUS; i++) { | 686 | mutex_lock(&relay_channels_mutex); |
628 | if (!chan->buf[i] || chan->buf[i] == prev) | 687 | if (chan->is_global && chan->buf[0]) |
629 | break; | 688 | relay_close_buf(chan->buf[0]); |
630 | relay_close_buf(chan->buf[i]); | 689 | else |
631 | prev = chan->buf[i]; | 690 | for_each_possible_cpu(i) |
632 | } | 691 | if (chan->buf[i]) |
692 | relay_close_buf(chan->buf[i]); | ||
633 | 693 | ||
634 | if (chan->last_toobig) | 694 | if (chan->last_toobig) |
635 | printk(KERN_WARNING "relay: one or more items not logged " | 695 | printk(KERN_WARNING "relay: one or more items not logged " |
636 | "[item size (%Zd) > sub-buffer size (%Zd)]\n", | 696 | "[item size (%Zd) > sub-buffer size (%Zd)]\n", |
637 | chan->last_toobig, chan->subbuf_size); | 697 | chan->last_toobig, chan->subbuf_size); |
638 | 698 | ||
699 | list_del(&chan->list); | ||
639 | kref_put(&chan->kref, relay_destroy_channel); | 700 | kref_put(&chan->kref, relay_destroy_channel); |
701 | mutex_unlock(&relay_channels_mutex); | ||
640 | } | 702 | } |
641 | EXPORT_SYMBOL_GPL(relay_close); | 703 | EXPORT_SYMBOL_GPL(relay_close); |
642 | 704 | ||
@@ -649,17 +711,20 @@ EXPORT_SYMBOL_GPL(relay_close); | |||
649 | void relay_flush(struct rchan *chan) | 711 | void relay_flush(struct rchan *chan) |
650 | { | 712 | { |
651 | unsigned int i; | 713 | unsigned int i; |
652 | struct rchan_buf *prev = NULL; | ||
653 | 714 | ||
654 | if (!chan) | 715 | if (!chan) |
655 | return; | 716 | return; |
656 | 717 | ||
657 | for (i = 0; i < NR_CPUS; i++) { | 718 | if (chan->is_global && chan->buf[0]) { |
658 | if (!chan->buf[i] || chan->buf[i] == prev) | 719 | relay_switch_subbuf(chan->buf[0], 0); |
659 | break; | 720 | return; |
660 | relay_switch_subbuf(chan->buf[i], 0); | ||
661 | prev = chan->buf[i]; | ||
662 | } | 721 | } |
722 | |||
723 | mutex_lock(&relay_channels_mutex); | ||
724 | for_each_possible_cpu(i) | ||
725 | if (chan->buf[i]) | ||
726 | relay_switch_subbuf(chan->buf[i], 0); | ||
727 | mutex_unlock(&relay_channels_mutex); | ||
663 | } | 728 | } |
664 | EXPORT_SYMBOL_GPL(relay_flush); | 729 | EXPORT_SYMBOL_GPL(relay_flush); |
665 | 730 | ||
@@ -684,7 +749,7 @@ static int relay_file_open(struct inode *inode, struct file *filp) | |||
684 | * @filp: the file | 749 | * @filp: the file |
685 | * @vma: the vma describing what to map | 750 | * @vma: the vma describing what to map |
686 | * | 751 | * |
687 | * Calls upon relay_mmap_buf to map the file into user space. | 752 | * Calls upon relay_mmap_buf() to map the file into user space. |
688 | */ | 753 | */ |
689 | static int relay_file_mmap(struct file *filp, struct vm_area_struct *vma) | 754 | static int relay_file_mmap(struct file *filp, struct vm_area_struct *vma) |
690 | { | 755 | { |
@@ -826,7 +891,7 @@ static size_t relay_file_read_subbuf_avail(size_t read_pos, | |||
826 | * @read_pos: file read position | 891 | * @read_pos: file read position |
827 | * @buf: relay channel buffer | 892 | * @buf: relay channel buffer |
828 | * | 893 | * |
829 | * If the read_pos is in the middle of padding, return the | 894 | * If the @read_pos is in the middle of padding, return the |
830 | * position of the first actually available byte, otherwise | 895 | * position of the first actually available byte, otherwise |
831 | * return the original value. | 896 | * return the original value. |
832 | */ | 897 | */ |
@@ -1022,3 +1087,12 @@ const struct file_operations relay_file_operations = { | |||
1022 | .sendfile = relay_file_sendfile, | 1087 | .sendfile = relay_file_sendfile, |
1023 | }; | 1088 | }; |
1024 | EXPORT_SYMBOL_GPL(relay_file_operations); | 1089 | EXPORT_SYMBOL_GPL(relay_file_operations); |
1090 | |||
1091 | static __init int relay_init(void) | ||
1092 | { | ||
1093 | |||
1094 | hotcpu_notifier(relay_hotcpu_callback, 0); | ||
1095 | return 0; | ||
1096 | } | ||
1097 | |||
1098 | module_init(relay_init); | ||