diff options
Diffstat (limited to 'kernel/relay.c')
| -rw-r--r-- | kernel/relay.c | 182 |
1 files changed, 152 insertions, 30 deletions
diff --git a/kernel/relay.c b/kernel/relay.c index 7de644cdec43..8d13a7855c08 100644 --- a/kernel/relay.c +++ b/kernel/relay.c | |||
| @@ -407,6 +407,35 @@ void relay_reset(struct rchan *chan) | |||
| 407 | } | 407 | } |
| 408 | EXPORT_SYMBOL_GPL(relay_reset); | 408 | EXPORT_SYMBOL_GPL(relay_reset); |
| 409 | 409 | ||
| 410 | static inline void relay_set_buf_dentry(struct rchan_buf *buf, | ||
| 411 | struct dentry *dentry) | ||
| 412 | { | ||
| 413 | buf->dentry = dentry; | ||
| 414 | buf->dentry->d_inode->i_size = buf->early_bytes; | ||
| 415 | } | ||
| 416 | |||
| 417 | static struct dentry *relay_create_buf_file(struct rchan *chan, | ||
| 418 | struct rchan_buf *buf, | ||
| 419 | unsigned int cpu) | ||
| 420 | { | ||
| 421 | struct dentry *dentry; | ||
| 422 | char *tmpname; | ||
| 423 | |||
| 424 | tmpname = kzalloc(NAME_MAX + 1, GFP_KERNEL); | ||
| 425 | if (!tmpname) | ||
| 426 | return NULL; | ||
| 427 | snprintf(tmpname, NAME_MAX, "%s%d", chan->base_filename, cpu); | ||
| 428 | |||
| 429 | /* Create file in fs */ | ||
| 430 | dentry = chan->cb->create_buf_file(tmpname, chan->parent, | ||
| 431 | S_IRUSR, buf, | ||
| 432 | &chan->is_global); | ||
| 433 | |||
| 434 | kfree(tmpname); | ||
| 435 | |||
| 436 | return dentry; | ||
| 437 | } | ||
| 438 | |||
| 410 | /* | 439 | /* |
| 411 | * relay_open_buf - create a new relay channel buffer | 440 | * relay_open_buf - create a new relay channel buffer |
| 412 | * | 441 | * |
| @@ -416,45 +445,34 @@ static struct rchan_buf *relay_open_buf(struct rchan *chan, unsigned int cpu) | |||
| 416 | { | 445 | { |
| 417 | struct rchan_buf *buf = NULL; | 446 | struct rchan_buf *buf = NULL; |
| 418 | struct dentry *dentry; | 447 | struct dentry *dentry; |
| 419 | char *tmpname; | ||
| 420 | 448 | ||
| 421 | if (chan->is_global) | 449 | if (chan->is_global) |
| 422 | return chan->buf[0]; | 450 | return chan->buf[0]; |
| 423 | 451 | ||
| 424 | tmpname = kzalloc(NAME_MAX + 1, GFP_KERNEL); | ||
| 425 | if (!tmpname) | ||
| 426 | goto end; | ||
| 427 | snprintf(tmpname, NAME_MAX, "%s%d", chan->base_filename, cpu); | ||
| 428 | |||
| 429 | buf = relay_create_buf(chan); | 452 | buf = relay_create_buf(chan); |
| 430 | if (!buf) | 453 | if (!buf) |
| 431 | goto free_name; | 454 | return NULL; |
| 455 | |||
| 456 | if (chan->has_base_filename) { | ||
| 457 | dentry = relay_create_buf_file(chan, buf, cpu); | ||
| 458 | if (!dentry) | ||
| 459 | goto free_buf; | ||
| 460 | relay_set_buf_dentry(buf, dentry); | ||
| 461 | } | ||
| 432 | 462 | ||
| 433 | buf->cpu = cpu; | 463 | buf->cpu = cpu; |
| 434 | __relay_reset(buf, 1); | 464 | __relay_reset(buf, 1); |
| 435 | 465 | ||
| 436 | /* Create file in fs */ | ||
| 437 | dentry = chan->cb->create_buf_file(tmpname, chan->parent, S_IRUSR, | ||
| 438 | buf, &chan->is_global); | ||
| 439 | if (!dentry) | ||
| 440 | goto free_buf; | ||
| 441 | |||
| 442 | buf->dentry = dentry; | ||
| 443 | |||
| 444 | if(chan->is_global) { | 466 | if(chan->is_global) { |
| 445 | chan->buf[0] = buf; | 467 | chan->buf[0] = buf; |
| 446 | buf->cpu = 0; | 468 | buf->cpu = 0; |
| 447 | } | 469 | } |
| 448 | 470 | ||
| 449 | goto free_name; | 471 | return buf; |
| 450 | 472 | ||
| 451 | free_buf: | 473 | free_buf: |
| 452 | relay_destroy_buf(buf); | 474 | relay_destroy_buf(buf); |
| 453 | buf = NULL; | 475 | return NULL; |
| 454 | free_name: | ||
| 455 | kfree(tmpname); | ||
| 456 | end: | ||
| 457 | return buf; | ||
| 458 | } | 476 | } |
| 459 | 477 | ||
| 460 | /** | 478 | /** |
| @@ -537,8 +555,8 @@ static int __cpuinit relay_hotcpu_callback(struct notifier_block *nb, | |||
| 537 | 555 | ||
| 538 | /** | 556 | /** |
| 539 | * relay_open - create a new relay channel | 557 | * relay_open - create a new relay channel |
| 540 | * @base_filename: base name of files to create | 558 | * @base_filename: base name of files to create, %NULL for buffering only |
| 541 | * @parent: dentry of parent directory, %NULL for root directory | 559 | * @parent: dentry of parent directory, %NULL for root directory or buffer |
| 542 | * @subbuf_size: size of sub-buffers | 560 | * @subbuf_size: size of sub-buffers |
| 543 | * @n_subbufs: number of sub-buffers | 561 | * @n_subbufs: number of sub-buffers |
| 544 | * @cb: client callback functions | 562 | * @cb: client callback functions |
| @@ -560,8 +578,6 @@ struct rchan *relay_open(const char *base_filename, | |||
| 560 | { | 578 | { |
| 561 | unsigned int i; | 579 | unsigned int i; |
| 562 | struct rchan *chan; | 580 | struct rchan *chan; |
| 563 | if (!base_filename) | ||
| 564 | return NULL; | ||
| 565 | 581 | ||
| 566 | if (!(subbuf_size && n_subbufs)) | 582 | if (!(subbuf_size && n_subbufs)) |
| 567 | return NULL; | 583 | return NULL; |
| @@ -576,7 +592,10 @@ struct rchan *relay_open(const char *base_filename, | |||
| 576 | chan->alloc_size = FIX_SIZE(subbuf_size * n_subbufs); | 592 | chan->alloc_size = FIX_SIZE(subbuf_size * n_subbufs); |
| 577 | chan->parent = parent; | 593 | chan->parent = parent; |
| 578 | chan->private_data = private_data; | 594 | chan->private_data = private_data; |
| 579 | strlcpy(chan->base_filename, base_filename, NAME_MAX); | 595 | if (base_filename) { |
| 596 | chan->has_base_filename = 1; | ||
| 597 | strlcpy(chan->base_filename, base_filename, NAME_MAX); | ||
| 598 | } | ||
| 580 | setup_callbacks(chan, cb); | 599 | setup_callbacks(chan, cb); |
| 581 | kref_init(&chan->kref); | 600 | kref_init(&chan->kref); |
| 582 | 601 | ||
| @@ -604,6 +623,94 @@ free_bufs: | |||
| 604 | } | 623 | } |
| 605 | EXPORT_SYMBOL_GPL(relay_open); | 624 | EXPORT_SYMBOL_GPL(relay_open); |
| 606 | 625 | ||
| 626 | struct rchan_percpu_buf_dispatcher { | ||
| 627 | struct rchan_buf *buf; | ||
| 628 | struct dentry *dentry; | ||
| 629 | }; | ||
| 630 | |||
| 631 | /* Called in atomic context. */ | ||
| 632 | static void __relay_set_buf_dentry(void *info) | ||
| 633 | { | ||
| 634 | struct rchan_percpu_buf_dispatcher *p = info; | ||
| 635 | |||
| 636 | relay_set_buf_dentry(p->buf, p->dentry); | ||
| 637 | } | ||
| 638 | |||
| 639 | /** | ||
| 640 | * relay_late_setup_files - triggers file creation | ||
| 641 | * @chan: channel to operate on | ||
| 642 | * @base_filename: base name of files to create | ||
| 643 | * @parent: dentry of parent directory, %NULL for root directory | ||
| 644 | * | ||
| 645 | * Returns 0 if successful, non-zero otherwise. | ||
| 646 | * | ||
| 647 | * Use to setup files for a previously buffer-only channel. | ||
| 648 | * Useful to do early tracing in kernel, before VFS is up, for example. | ||
| 649 | */ | ||
| 650 | int relay_late_setup_files(struct rchan *chan, | ||
| 651 | const char *base_filename, | ||
| 652 | struct dentry *parent) | ||
| 653 | { | ||
| 654 | int err = 0; | ||
| 655 | unsigned int i, curr_cpu; | ||
| 656 | unsigned long flags; | ||
| 657 | struct dentry *dentry; | ||
| 658 | struct rchan_percpu_buf_dispatcher disp; | ||
| 659 | |||
| 660 | if (!chan || !base_filename) | ||
| 661 | return -EINVAL; | ||
| 662 | |||
| 663 | strlcpy(chan->base_filename, base_filename, NAME_MAX); | ||
| 664 | |||
| 665 | mutex_lock(&relay_channels_mutex); | ||
| 666 | /* Is chan already set up? */ | ||
| 667 | if (unlikely(chan->has_base_filename)) | ||
| 668 | return -EEXIST; | ||
| 669 | chan->has_base_filename = 1; | ||
| 670 | chan->parent = parent; | ||
| 671 | curr_cpu = get_cpu(); | ||
| 672 | /* | ||
| 673 | * The CPU hotplug notifier ran before us and created buffers with | ||
| 674 | * no files associated. So it's safe to call relay_setup_buf_file() | ||
| 675 | * on all currently online CPUs. | ||
| 676 | */ | ||
| 677 | for_each_online_cpu(i) { | ||
| 678 | if (unlikely(!chan->buf[i])) { | ||
| 679 | printk(KERN_ERR "relay_late_setup_files: CPU %u " | ||
| 680 | "has no buffer, it must have!\n", i); | ||
| 681 | BUG(); | ||
| 682 | err = -EINVAL; | ||
| 683 | break; | ||
| 684 | } | ||
| 685 | |||
| 686 | dentry = relay_create_buf_file(chan, chan->buf[i], i); | ||
| 687 | if (unlikely(!dentry)) { | ||
| 688 | err = -EINVAL; | ||
| 689 | break; | ||
| 690 | } | ||
| 691 | |||
| 692 | if (curr_cpu == i) { | ||
| 693 | local_irq_save(flags); | ||
| 694 | relay_set_buf_dentry(chan->buf[i], dentry); | ||
| 695 | local_irq_restore(flags); | ||
| 696 | } else { | ||
| 697 | disp.buf = chan->buf[i]; | ||
| 698 | disp.dentry = dentry; | ||
| 699 | smp_mb(); | ||
| 700 | /* relay_channels_mutex must be held, so wait. */ | ||
| 701 | err = smp_call_function_single(i, | ||
| 702 | __relay_set_buf_dentry, | ||
| 703 | &disp, 1); | ||
| 704 | } | ||
| 705 | if (unlikely(err)) | ||
| 706 | break; | ||
| 707 | } | ||
| 708 | put_cpu(); | ||
| 709 | mutex_unlock(&relay_channels_mutex); | ||
| 710 | |||
| 711 | return err; | ||
| 712 | } | ||
| 713 | |||
| 607 | /** | 714 | /** |
| 608 | * relay_switch_subbuf - switch to a new sub-buffer | 715 | * relay_switch_subbuf - switch to a new sub-buffer |
| 609 | * @buf: channel buffer | 716 | * @buf: channel buffer |
| @@ -627,8 +734,13 @@ size_t relay_switch_subbuf(struct rchan_buf *buf, size_t length) | |||
| 627 | old_subbuf = buf->subbufs_produced % buf->chan->n_subbufs; | 734 | old_subbuf = buf->subbufs_produced % buf->chan->n_subbufs; |
| 628 | buf->padding[old_subbuf] = buf->prev_padding; | 735 | buf->padding[old_subbuf] = buf->prev_padding; |
| 629 | buf->subbufs_produced++; | 736 | buf->subbufs_produced++; |
| 630 | buf->dentry->d_inode->i_size += buf->chan->subbuf_size - | 737 | if (buf->dentry) |
| 631 | buf->padding[old_subbuf]; | 738 | buf->dentry->d_inode->i_size += |
| 739 | buf->chan->subbuf_size - | ||
| 740 | buf->padding[old_subbuf]; | ||
| 741 | else | ||
| 742 | buf->early_bytes += buf->chan->subbuf_size - | ||
| 743 | buf->padding[old_subbuf]; | ||
| 632 | smp_mb(); | 744 | smp_mb(); |
| 633 | if (waitqueue_active(&buf->read_wait)) | 745 | if (waitqueue_active(&buf->read_wait)) |
| 634 | /* | 746 | /* |
| @@ -832,6 +944,10 @@ static void relay_file_read_consume(struct rchan_buf *buf, | |||
| 832 | size_t n_subbufs = buf->chan->n_subbufs; | 944 | size_t n_subbufs = buf->chan->n_subbufs; |
| 833 | size_t read_subbuf; | 945 | size_t read_subbuf; |
| 834 | 946 | ||
| 947 | if (buf->subbufs_produced == buf->subbufs_consumed && | ||
| 948 | buf->offset == buf->bytes_consumed) | ||
| 949 | return; | ||
| 950 | |||
| 835 | if (buf->bytes_consumed + bytes_consumed > subbuf_size) { | 951 | if (buf->bytes_consumed + bytes_consumed > subbuf_size) { |
| 836 | relay_subbufs_consumed(buf->chan, buf->cpu, 1); | 952 | relay_subbufs_consumed(buf->chan, buf->cpu, 1); |
| 837 | buf->bytes_consumed = 0; | 953 | buf->bytes_consumed = 0; |
| @@ -863,6 +979,8 @@ static int relay_file_read_avail(struct rchan_buf *buf, size_t read_pos) | |||
| 863 | 979 | ||
| 864 | relay_file_read_consume(buf, read_pos, 0); | 980 | relay_file_read_consume(buf, read_pos, 0); |
| 865 | 981 | ||
| 982 | consumed = buf->subbufs_consumed; | ||
| 983 | |||
| 866 | if (unlikely(buf->offset > subbuf_size)) { | 984 | if (unlikely(buf->offset > subbuf_size)) { |
| 867 | if (produced == consumed) | 985 | if (produced == consumed) |
| 868 | return 0; | 986 | return 0; |
| @@ -881,8 +999,12 @@ static int relay_file_read_avail(struct rchan_buf *buf, size_t read_pos) | |||
| 881 | if (consumed > produced) | 999 | if (consumed > produced) |
| 882 | produced += n_subbufs * subbuf_size; | 1000 | produced += n_subbufs * subbuf_size; |
| 883 | 1001 | ||
| 884 | if (consumed == produced) | 1002 | if (consumed == produced) { |
| 1003 | if (buf->offset == subbuf_size && | ||
| 1004 | buf->subbufs_produced > buf->subbufs_consumed) | ||
| 1005 | return 1; | ||
| 885 | return 0; | 1006 | return 0; |
| 1007 | } | ||
| 886 | 1008 | ||
| 887 | return 1; | 1009 | return 1; |
| 888 | } | 1010 | } |
| @@ -1237,4 +1359,4 @@ static __init int relay_init(void) | |||
| 1237 | return 0; | 1359 | return 0; |
| 1238 | } | 1360 | } |
| 1239 | 1361 | ||
| 1240 | module_init(relay_init); | 1362 | early_initcall(relay_init); |
