aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/relay.c180
1 files changed, 127 insertions, 53 deletions
diff --git a/kernel/relay.c b/kernel/relay.c
index 284e2e8b4eed..ef923f6de2e7 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 */
26static DEFINE_MUTEX(relay_channels_mutex);
27static 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);
@@ -362,51 +370,69 @@ static void __relay_reset(struct rchan_buf *buf, unsigned int init)
362void relay_reset(struct rchan *chan) 370void 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}
377EXPORT_SYMBOL_GPL(relay_reset); 388EXPORT_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 */
384static struct rchan_buf *relay_open_buf(struct rchan *chan, 395static 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
431free_buf:
432 relay_destroy_buf(buf);
433free_name:
434 kfree(tmpname);
435end:
410 return buf; 436 return buf;
411} 437}
412 438
@@ -448,12 +474,54 @@ 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 */
485static 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 *
@@ -466,13 +534,11 @@ 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
510free_bufs: 573free_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
520free_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}
524EXPORT_SYMBOL_GPL(relay_open); 584EXPORT_SYMBOL_GPL(relay_open);
@@ -619,24 +679,26 @@ EXPORT_SYMBOL_GPL(relay_subbufs_consumed);
619void relay_close(struct rchan *chan) 679void 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}
641EXPORT_SYMBOL_GPL(relay_close); 703EXPORT_SYMBOL_GPL(relay_close);
642 704
@@ -649,17 +711,20 @@ EXPORT_SYMBOL_GPL(relay_close);
649void relay_flush(struct rchan *chan) 711void 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}
664EXPORT_SYMBOL_GPL(relay_flush); 729EXPORT_SYMBOL_GPL(relay_flush);
665 730
@@ -1022,3 +1087,12 @@ const struct file_operations relay_file_operations = {
1022 .sendfile = relay_file_sendfile, 1087 .sendfile = relay_file_sendfile,
1023}; 1088};
1024EXPORT_SYMBOL_GPL(relay_file_operations); 1089EXPORT_SYMBOL_GPL(relay_file_operations);
1090
1091static __init int relay_init(void)
1092{
1093
1094 hotcpu_notifier(relay_hotcpu_callback, 0);
1095 return 0;
1096}
1097
1098module_init(relay_init);