aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorMathieu Desnoyers <mathieu.desnoyers@polymtl.ca>2007-02-10 04:45:05 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-11 13:51:28 -0500
commit23c887522e912ca494950796a95df8dd210f4b01 (patch)
treeda8c244fd7fd7eef7a413ad8df2f19b32d4a7c52 /kernel
parent138c5d258cf06c278f5d7fe0a806e50fe413a08f (diff)
[PATCH] Relay: add CPU hotplug support
Mathieu originally needed to add this for tracing Xen, but it's something that's needed for any application that can be tracing while cpus are added. unplug isn't supported by this patch. The thought was that at minumum a new buffer needs to be added when a cpu comes up, but it wasn't worth the effort to remove buffers on cpu down since they'd be freed soon anyway when the channel was closed. [zanussi@us.ibm.com: avoid lock_cpu_hotplug deadlock] Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca> Cc: Tom Zanussi <zanussi@us.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
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);