Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 47522
b: refs/heads/master
c: 23c8875
h: refs/heads/master
v: v3
  • Loading branch information
Mathieu Desnoyers authored and Linus Torvalds committed Feb 11, 2007
1 parent de029bf commit 1002f16
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 60 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 138c5d258cf06c278f5d7fe0a806e50fe413a08f
refs/heads/master: 23c887522e912ca494950796a95df8dd210f4b01
9 changes: 7 additions & 2 deletions trunk/Documentation/filesystems/relay.txt
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ TBD(curr. line MT:/API/)
channel management functions:

relay_open(base_filename, parent, subbuf_size, n_subbufs,
callbacks)
callbacks, private_data)
relay_close(chan)
relay_flush(chan)
relay_reset(chan)
Expand Down Expand Up @@ -251,7 +251,7 @@ static struct rchan_callbacks relay_callbacks =

And an example relay_open() invocation using them:

chan = relay_open("cpu", NULL, SUBBUF_SIZE, N_SUBBUFS, &relay_callbacks);
chan = relay_open("cpu", NULL, SUBBUF_SIZE, N_SUBBUFS, &relay_callbacks, NULL);

If the create_buf_file() callback fails, or isn't defined, channel
creation and thus relay_open() will fail.
Expand Down Expand Up @@ -289,6 +289,11 @@ they use the proper locking for such a buffer, either by wrapping
writes in a spinlock, or by copying a write function from relay.h and
creating a local version that internally does the proper locking.

The private_data passed into relay_open() allows clients to associate
user-defined data with a channel, and is immediately available
(including in create_buf_file()) via chan->private_data or
buf->chan->private_data.

Channel 'modes'
---------------

Expand Down
3 changes: 1 addition & 2 deletions trunk/block/blktrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -363,10 +363,9 @@ static int blk_trace_setup(request_queue_t *q, struct block_device *bdev,
if (!bt->dropped_file)
goto err;

bt->rchan = relay_open("trace", dir, buts.buf_size, buts.buf_nr, &blk_relay_callbacks);
bt->rchan = relay_open("trace", dir, buts.buf_size, buts.buf_nr, &blk_relay_callbacks, bt);
if (!bt->rchan)
goto err;
bt->rchan->private_data = bt;

bt->act_mask = buts.act_mask;
if (!bt->act_mask)
Expand Down
9 changes: 7 additions & 2 deletions trunk/include/linux/relay.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
/*
* Tracks changes to rchan/rchan_buf structs
*/
#define RELAYFS_CHANNEL_VERSION 6
#define RELAYFS_CHANNEL_VERSION 7

/*
* Per-cpu relay channel buffer
Expand Down Expand Up @@ -64,6 +64,10 @@ struct rchan
void *private_data; /* for user-defined data */
size_t last_toobig; /* tried to log event > subbuf size */
struct rchan_buf *buf[NR_CPUS]; /* per-cpu channel buffers */
int is_global; /* One global buffer ? */
struct list_head list; /* for channel list */
struct dentry *parent; /* parent dentry passed to open */
char base_filename[NAME_MAX]; /* saved base filename */
};

/*
Expand Down Expand Up @@ -162,7 +166,8 @@ struct rchan *relay_open(const char *base_filename,
struct dentry *parent,
size_t subbuf_size,
size_t n_subbufs,
struct rchan_callbacks *cb);
struct rchan_callbacks *cb,
void *private_data);
extern void relay_close(struct rchan *chan);
extern void relay_flush(struct rchan *chan);
extern void relay_subbufs_consumed(struct rchan *chan,
Expand Down
180 changes: 127 additions & 53 deletions trunk/kernel/relay.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
* Copyright (C) 1999-2005 - Karim Yaghmour (karim@opersys.com)
*
* Moved to kernel/relay.c by Paul Mundt, 2006.
* November 2006 - CPU hotplug support by Mathieu Desnoyers
* (mathieu.desnoyers@polymtl.ca)
*
* This file is released under the GPL.
*/
Expand All @@ -18,6 +20,11 @@
#include <linux/relay.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>
#include <linux/cpu.h>

/* list of open channels, for cpu hotplug */
static DEFINE_MUTEX(relay_channels_mutex);
static LIST_HEAD(relay_channels);

/*
* close() vm_op implementation for relay file mapping.
Expand Down Expand Up @@ -187,6 +194,7 @@ void relay_destroy_buf(struct rchan_buf *buf)
__free_page(buf->page_array[i]);
kfree(buf->page_array);
}
chan->buf[buf->cpu] = NULL;
kfree(buf->padding);
kfree(buf);
kref_put(&chan->kref, relay_destroy_channel);
Expand Down Expand Up @@ -362,51 +370,69 @@ static void __relay_reset(struct rchan_buf *buf, unsigned int init)
void relay_reset(struct rchan *chan)
{
unsigned int i;
struct rchan_buf *prev = NULL;

if (!chan)
return;

for (i = 0; i < NR_CPUS; i++) {
if (!chan->buf[i] || chan->buf[i] == prev)
break;
__relay_reset(chan->buf[i], 0);
prev = chan->buf[i];
if (chan->is_global && chan->buf[0]) {
__relay_reset(chan->buf[0], 0);
return;
}

mutex_lock(&relay_channels_mutex);
for_each_online_cpu(i)
if (chan->buf[i])
__relay_reset(chan->buf[i], 0);
mutex_unlock(&relay_channels_mutex);
}
EXPORT_SYMBOL_GPL(relay_reset);

/*
* relay_open_buf - create a new relay channel buffer
*
* Internal - used by relay_open().
* used by relay_open() and CPU hotplug.
*/
static struct rchan_buf *relay_open_buf(struct rchan *chan,
const char *filename,
struct dentry *parent,
int *is_global)
static struct rchan_buf *relay_open_buf(struct rchan *chan, unsigned int cpu)
{
struct rchan_buf *buf;
struct rchan_buf *buf = NULL;
struct dentry *dentry;
char *tmpname;

if (*is_global)
if (chan->is_global)
return chan->buf[0];

tmpname = kzalloc(NAME_MAX + 1, GFP_KERNEL);
if (!tmpname)
goto end;
snprintf(tmpname, NAME_MAX, "%s%d", chan->base_filename, cpu);

buf = relay_create_buf(chan);
if (!buf)
return NULL;
goto free_name;

buf->cpu = cpu;
__relay_reset(buf, 1);

/* Create file in fs */
dentry = chan->cb->create_buf_file(filename, parent, S_IRUSR,
buf, is_global);
if (!dentry) {
relay_destroy_buf(buf);
return NULL;
}
dentry = chan->cb->create_buf_file(tmpname, chan->parent, S_IRUSR,
buf, &chan->is_global);
if (!dentry)
goto free_buf;

buf->dentry = dentry;
__relay_reset(buf, 1);

if(chan->is_global) {
chan->buf[0] = buf;
buf->cpu = 0;
}

goto free_name;

free_buf:
relay_destroy_buf(buf);
free_name:
kfree(tmpname);
end:
return buf;
}

Expand Down Expand Up @@ -447,13 +473,55 @@ static void setup_callbacks(struct rchan *chan,
chan->cb = cb;
}

/**
*
* relay_hotcpu_callback - CPU hotplug callback
* @nb: notifier block
* @action: hotplug action to take
* @hcpu: CPU number
*
* Returns the success/failure of the operation. (NOTIFY_OK, NOTIFY_BAD)
*/
static int __cpuinit relay_hotcpu_callback(struct notifier_block *nb,
unsigned long action,
void *hcpu)
{
unsigned int hotcpu = (unsigned long)hcpu;
struct rchan *chan;

switch(action) {
case CPU_UP_PREPARE:
mutex_lock(&relay_channels_mutex);
list_for_each_entry(chan, &relay_channels, list) {
if (chan->buf[hotcpu])
continue;
chan->buf[hotcpu] = relay_open_buf(chan, hotcpu);
if(!chan->buf[hotcpu]) {
printk(KERN_ERR
"relay_hotcpu_callback: cpu %d buffer "
"creation failed\n", hotcpu);
mutex_unlock(&relay_channels_mutex);
return NOTIFY_BAD;
}
}
mutex_unlock(&relay_channels_mutex);
break;
case CPU_DEAD:
/* No need to flush the cpu : will be flushed upon
* final relay_flush() call. */
break;
}
return NOTIFY_OK;
}

/**
* relay_open - create a new relay channel
* @base_filename: base name of files to create
* @parent: dentry of parent directory, %NULL for root directory
* @subbuf_size: size of sub-buffers
* @n_subbufs: number of sub-buffers
* @cb: client callback functions
* @private_data: user-defined data
*
* Returns channel pointer if successful, %NULL otherwise.
*
Expand All @@ -466,13 +534,11 @@ struct rchan *relay_open(const char *base_filename,
struct dentry *parent,
size_t subbuf_size,
size_t n_subbufs,
struct rchan_callbacks *cb)
struct rchan_callbacks *cb,
void *private_data)
{
unsigned int i;
struct rchan *chan;
char *tmpname;
int is_global = 0;

if (!base_filename)
return NULL;

Expand All @@ -487,38 +553,32 @@ struct rchan *relay_open(const char *base_filename,
chan->n_subbufs = n_subbufs;
chan->subbuf_size = subbuf_size;
chan->alloc_size = FIX_SIZE(subbuf_size * n_subbufs);
chan->parent = parent;
chan->private_data = private_data;
strlcpy(chan->base_filename, base_filename, NAME_MAX);
setup_callbacks(chan, cb);
kref_init(&chan->kref);

tmpname = kmalloc(NAME_MAX + 1, GFP_KERNEL);
if (!tmpname)
goto free_chan;

mutex_lock(&relay_channels_mutex);
for_each_online_cpu(i) {
sprintf(tmpname, "%s%d", base_filename, i);
chan->buf[i] = relay_open_buf(chan, tmpname, parent,
&is_global);
chan->buf[i] = relay_open_buf(chan, i);
if (!chan->buf[i])
goto free_bufs;

chan->buf[i]->cpu = i;
}
list_add(&chan->list, &relay_channels);
mutex_unlock(&relay_channels_mutex);

kfree(tmpname);
return chan;

free_bufs:
for (i = 0; i < NR_CPUS; i++) {
for_each_online_cpu(i) {
if (!chan->buf[i])
break;
relay_close_buf(chan->buf[i]);
if (is_global)
break;
}
kfree(tmpname);

free_chan:
kref_put(&chan->kref, relay_destroy_channel);
mutex_unlock(&relay_channels_mutex);
return NULL;
}
EXPORT_SYMBOL_GPL(relay_open);
Expand Down Expand Up @@ -619,24 +679,26 @@ EXPORT_SYMBOL_GPL(relay_subbufs_consumed);
void relay_close(struct rchan *chan)
{
unsigned int i;
struct rchan_buf *prev = NULL;

if (!chan)
return;

for (i = 0; i < NR_CPUS; i++) {
if (!chan->buf[i] || chan->buf[i] == prev)
break;
relay_close_buf(chan->buf[i]);
prev = chan->buf[i];
}
mutex_lock(&relay_channels_mutex);
if (chan->is_global && chan->buf[0])
relay_close_buf(chan->buf[0]);
else
for_each_possible_cpu(i)
if (chan->buf[i])
relay_close_buf(chan->buf[i]);

if (chan->last_toobig)
printk(KERN_WARNING "relay: one or more items not logged "
"[item size (%Zd) > sub-buffer size (%Zd)]\n",
chan->last_toobig, chan->subbuf_size);

list_del(&chan->list);
kref_put(&chan->kref, relay_destroy_channel);
mutex_unlock(&relay_channels_mutex);
}
EXPORT_SYMBOL_GPL(relay_close);

Expand All @@ -649,17 +711,20 @@ EXPORT_SYMBOL_GPL(relay_close);
void relay_flush(struct rchan *chan)
{
unsigned int i;
struct rchan_buf *prev = NULL;

if (!chan)
return;

for (i = 0; i < NR_CPUS; i++) {
if (!chan->buf[i] || chan->buf[i] == prev)
break;
relay_switch_subbuf(chan->buf[i], 0);
prev = chan->buf[i];
if (chan->is_global && chan->buf[0]) {
relay_switch_subbuf(chan->buf[0], 0);
return;
}

mutex_lock(&relay_channels_mutex);
for_each_possible_cpu(i)
if (chan->buf[i])
relay_switch_subbuf(chan->buf[i], 0);
mutex_unlock(&relay_channels_mutex);
}
EXPORT_SYMBOL_GPL(relay_flush);

Expand Down Expand Up @@ -1022,3 +1087,12 @@ const struct file_operations relay_file_operations = {
.sendfile = relay_file_sendfile,
};
EXPORT_SYMBOL_GPL(relay_file_operations);

static __init int relay_init(void)
{

hotcpu_notifier(relay_hotcpu_callback, 0);
return 0;
}

module_init(relay_init);

0 comments on commit 1002f16

Please sign in to comment.