diff options
-rw-r--r-- | Documentation/filesystems/relay.txt | 10 | ||||
-rw-r--r-- | include/linux/relay.h | 5 | ||||
-rw-r--r-- | kernel/relay.c | 170 |
3 files changed, 156 insertions, 29 deletions
diff --git a/Documentation/filesystems/relay.txt b/Documentation/filesystems/relay.txt index 094f2d2f38b1..510b722667ac 100644 --- a/Documentation/filesystems/relay.txt +++ b/Documentation/filesystems/relay.txt | |||
@@ -294,6 +294,16 @@ user-defined data with a channel, and is immediately available | |||
294 | (including in create_buf_file()) via chan->private_data or | 294 | (including in create_buf_file()) via chan->private_data or |
295 | buf->chan->private_data. | 295 | buf->chan->private_data. |
296 | 296 | ||
297 | Buffer-only channels | ||
298 | -------------------- | ||
299 | |||
300 | These channels have no files associated and can be created with | ||
301 | relay_open(NULL, NULL, ...). Such channels are useful in scenarios such | ||
302 | as when doing early tracing in the kernel, before the VFS is up. In these | ||
303 | cases, one may open a buffer-only channel and then call | ||
304 | relay_late_setup_files() when the kernel is ready to handle files, | ||
305 | to expose the buffered data to the userspace. | ||
306 | |||
297 | Channel 'modes' | 307 | Channel 'modes' |
298 | --------------- | 308 | --------------- |
299 | 309 | ||
diff --git a/include/linux/relay.h b/include/linux/relay.h index 6cd8c4425fc7..953fc055e875 100644 --- a/include/linux/relay.h +++ b/include/linux/relay.h | |||
@@ -48,6 +48,7 @@ struct rchan_buf | |||
48 | size_t *padding; /* padding counts per sub-buffer */ | 48 | size_t *padding; /* padding counts per sub-buffer */ |
49 | size_t prev_padding; /* temporary variable */ | 49 | size_t prev_padding; /* temporary variable */ |
50 | size_t bytes_consumed; /* bytes consumed in cur read subbuf */ | 50 | size_t bytes_consumed; /* bytes consumed in cur read subbuf */ |
51 | size_t early_bytes; /* bytes consumed before VFS inited */ | ||
51 | unsigned int cpu; /* this buf's cpu */ | 52 | unsigned int cpu; /* this buf's cpu */ |
52 | } ____cacheline_aligned; | 53 | } ____cacheline_aligned; |
53 | 54 | ||
@@ -68,6 +69,7 @@ struct rchan | |||
68 | int is_global; /* One global buffer ? */ | 69 | int is_global; /* One global buffer ? */ |
69 | struct list_head list; /* for channel list */ | 70 | struct list_head list; /* for channel list */ |
70 | struct dentry *parent; /* parent dentry passed to open */ | 71 | struct dentry *parent; /* parent dentry passed to open */ |
72 | int has_base_filename; /* has a filename associated? */ | ||
71 | char base_filename[NAME_MAX]; /* saved base filename */ | 73 | char base_filename[NAME_MAX]; /* saved base filename */ |
72 | }; | 74 | }; |
73 | 75 | ||
@@ -169,6 +171,9 @@ struct rchan *relay_open(const char *base_filename, | |||
169 | size_t n_subbufs, | 171 | size_t n_subbufs, |
170 | struct rchan_callbacks *cb, | 172 | struct rchan_callbacks *cb, |
171 | void *private_data); | 173 | void *private_data); |
174 | extern int relay_late_setup_files(struct rchan *chan, | ||
175 | const char *base_filename, | ||
176 | struct dentry *parent); | ||
172 | extern void relay_close(struct rchan *chan); | 177 | extern void relay_close(struct rchan *chan); |
173 | extern void relay_flush(struct rchan *chan); | 178 | extern void relay_flush(struct rchan *chan); |
174 | extern void relay_subbufs_consumed(struct rchan *chan, | 179 | extern void relay_subbufs_consumed(struct rchan *chan, |
diff --git a/kernel/relay.c b/kernel/relay.c index 7de644cdec43..04006ef970b8 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 | /* |
@@ -1237,4 +1349,4 @@ static __init int relay_init(void) | |||
1237 | return 0; | 1349 | return 0; |
1238 | } | 1350 | } |
1239 | 1351 | ||
1240 | module_init(relay_init); | 1352 | early_initcall(relay_init); |