Re: [PATCH] Relay CPU hotplug support

Mathieu Desnoyers <[email protected]>
Newsgroups gmane.linux.kernel.tracing
Message-ID <20061128152217.GA15266@Krystal>
Hi Tom,

* Tom Zanussi ([email protected]) wrote:
> Mathieu Desnoyers writes:
>  > Hi Tom,
>  > 
>  > Here is my version of the relay patch for CPU hotplug support. It uses a
>  > channel list within relay, as you suggested. The patch is based on a 2.6.18
>  > kernel.
>  > 
>  > Comments are welcome,
>  > 
> 
> Hi Mathieu,
> 
> I still need to go over the patch in detail, but there are a couple of
> things I don't quite understand yet - could you explain them a little
> to get me on the right track (see below)?
> 
> [...]
> 
>  >  /**
>  >   *	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)
>  > +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) {
>  > +		kref_get(&chan->buf[0]->krefw);
>  >  		return chan->buf[0];
>  > +	}
>  > +
>  > +	tmpname = kmalloc(NAME_MAX + 1, GFP_KERNEL);
>  > +	if (!tmpname)
>  > +		goto end;
>  > +	sprintf(tmpname, "%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;
>  > +
>  > +	if(chan->is_global) {
>  > +		chan->buf[0] = buf;
>  > +		buf->cpu = 0;
>  >  	}
>  > 
>  >  	buf->dentry = dentry;
>  > -	__relay_reset(buf, 1);
>  > +	goto free_name;
>  > 
>  > +free_buf:
>  > +	relay_destroy_buf(buf);
>  > +free_name:
>  > +	kfree(tmpname);
>  > +end:
>  >  	return buf;
>  >  }
>  > +EXPORT_SYMBOL_GPL(relay_open_buf);
>  > 
> 
> I understand why you changed relay_open_buf(), which makes sense, but
> I don't see why it's exported now.
> 

Sorry, it's a leftover from my own changes where I did not use any list. You can
remove the export.

>  >  /**
>  > - *	relay_close_buf - close a channel buffer
>  > - *	@buf: channel buffer
>  > + *	relay_close_write_buf - close write to a channel buffer
>  > + *	@kref: buffer writers reference
>  >   *
>  >   *	Marks the buffer finalized and restores the default callbacks.
>  >   *	The channel buffer and channel buffer data structure are then freed
>  >   *	automatically when the last reference is given up.
>  >   */
>  > -static inline void relay_close_buf(struct rchan_buf *buf)
>  > +static void relay_close_write_buf(struct kref *kref)
>  >  {
>  > +	struct rchan_buf *buf = container_of(kref, struct rchan_buf, krefw);
>  > +
>  >  	buf->finalized = 1;
>  >  	cancel_delayed_work(&buf->wake_readers);
>  >  	flush_scheduled_work();
>  >  	kref_put(&buf->kref, relay_remove_buf);
>  >  }
>  > 
>  > +/**
>  > + *	relay_close_buf - close a channel buffer
>  > + *	@buf: channel buffer
>  > + *	
>  > + *	Remove a writer reference.
>  > + */
>  > +
>  > +void relay_close_buf(struct rchan_buf *buf)
>  > +{
>  > +	kref_put(&buf->krefw, relay_close_write_buf);
>  > +}
>  > +EXPORT_SYMBOL_GPL(relay_close_buf);
>  > +
> 
> I don't really understand the additional kref (buf->krefw), or why you
> split relay_close_buf() and exported it.
> 

We can remove the export here too. In fact, I removed the prototypes from
relay.h, but forgot to remove the export.

Now for buf->krefw :

I wanted to separate the fact that a buffer is held by a reader from the fact
that a buffer is held by a writer. By doing this, we can support the is_global
channels more efficiently :

for example, if we have 8 CPUs with a is_global channel, what we want is to wait
until the last writer closes the buffer. Only at that point do we want to
finalize the buffer (this is why the finalize and flush work is done in the
function called upon krefw final put). But, we only want to free the buffer once
the last reader released it : this is why the original kref is still there.


> [...]
> 
>  > +
>  > +/**
>  >   *	relay_open - create a new relay channel
>  >   *	@base_filename: base name of files to create
>  >   *	@parent: dentry of parent directory, NULL for root directory
>  > @@ -464,13 +550,11 @@ struct rchan *relay_open(const char *bas
>  >  			 struct dentry *parent,
>  >  			 size_t subbuf_size,
>  >  			 size_t n_subbufs,
>  > -			 struct rchan_callbacks *cb)
>  > +			 struct rchan_callbacks *cb,
>  > +			 void *private_data)
>  >  {
> 
> Also, why you had to add private_data to relay_open() - I think it
> would be better to avoid changing existing API functions if
> possible...
> 

It's there because I need, in the client, to have access to the private_data
when the create_buf_file is called. The difference now is that this callback is
not only responsible for creating any client specific files and data structures
when relay_open is called, but it is also called when a CPU hotplug online event
occurs. So, what I could do before just after the call to relay_open (creation
of my private data) couldn't be done elegantly anymore without passing the
private_data to the relay_open call.

Thanks,

Mathieu


OpenPGP public key:              http://krystal.dyndns.org:8080/key/compudj.gpg
Key fingerprint:     8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.