[dm-devel] [PATCH v2 2/2 "v9"] dm: only initialize full request_queue for request-based device

Mike Snitzer snitzer at redhat.com
Tue May 25 12:49:13 UTC 2010


On Tue, May 25 2010 at  7:18am -0400,
Kiyoshi Ueda <k-ueda at ct.jp.nec.com> wrote:

> Hi Mike,
> 
> On 05/25/2010 08:46 AM +0900, Mike Snitzer wrote:
> > Index: linux-2.6/drivers/md/dm-ioctl.c
> > ===================================================================
> > --- linux-2.6.orig/drivers/md/dm-ioctl.c
> > +++ linux-2.6/drivers/md/dm-ioctl.c
> > @@ -1201,6 +1203,15 @@ static int table_load(struct dm_ioctl *p
> >  		goto out;
> >  	}
> >  
> > +	/* setup md->queue to reflect md's and table's type (may block) */
> > +	r = dm_setup_md_queue(md);
> > +	if (r) {
> > +		DMWARN("unable to setup device queue for this table.");
> > +		dm_table_destroy(t);
> > +		dm_unlock_md_type(md);
> > +		goto out;
> > +	}
> > +
> 
> dm_setup_md_queue() should be put just after dm_set_md_type() of patch#1.
> Then, you can make sure that dm_setup_md_queue() is called only once
> and dm_setup_md_queue() should be much simpler.

Good idea.

> > +/*
> > + * Fully initialize a request-based queue (->elevator, ->request_fn, etc).
> > + */
> > +static int dm_init_request_based_queue(struct mapped_device *md)
> > +{
> > +	struct request_queue *q = NULL;
> > +
> > +	/* Avoid re-initializing the queue if already fully initialized */
> > +	if (!md->queue->elevator) {
> > +		/* Fully initialize the queue */
> > +		q = blk_init_allocated_queue(md->queue, dm_request_fn, NULL);
> > +		if (!q)
> > +			return 0;
> 
> When blk_init_allocated_queue() fails, the block-layer seems not to
> guarantee that the queue is still available.

Ouch, yes this portion of blk_init_allocated_queue_node() is certainly
problematic:

        if (blk_init_free_list(q)) {
                kmem_cache_free(blk_requestq_cachep, q);
                return NULL;
        }

Cc'ing Jens as I think it would be advantageous for us to push the above
kmem_cache_free() into the callers where it really makes sense, e.g.:
blk_init_queue_node().

So on blk_init_allocated_queue_node() failure blk_init_queue_node() will
take care to cleanup the queue that it assumes it is managing
completely.

My patch (linux-2.6-block.git's commit: 01effb0) that split out
blk_init_allocated_queue_node() from blk_init_queue_node() opened up
this issue.  I'm fairly confident we'll get it fixed by the time 2.6.35
ships.

> You should create appropriate block-layer interfaces and/or take proper
> recovery action here.
> However, if the failure is not realistic, rather than complicating this
> patch, you can just put a big comment and WARN_ON() for now, and fix it
> in a separate patch-set.

I'll hold off on the WARN_ON().  I think we need the request_queue to
remain allocated even after blk_init_allocated_queue_node() failure.

> > +static void dm_clear_request_based_queue(struct mapped_device *md)
> > +{
> > +	if (dm_bio_based_md_queue(md))
> > +		return; /* queue already bio-based */
> > +
> > +	/* Unregister elevator from sysfs and clear ->request_fn */
> > +	elv_unregister_queue(md->queue);
> > +	md->queue->request_fn = NULL;
> > +}
> > +
> > +/*
> > + * Setup the DM device's queue based on md's type
> > + */
> > +int dm_setup_md_queue(struct mapped_device *md)
> > +{
> > +	BUG_ON(!mutex_is_locked(&md->type_lock));
> > +	BUG_ON(dm_unknown_md_type(md));
> > +
> > +	if (dm_request_based_md_type(md)) {
> > +		if (!dm_init_request_based_queue(md)) {
> > +			DMWARN("Cannot initialize queue for Request-based dm");
> > +			return -EINVAL;
> > +		}
> > +	} else if (dm_bio_based_md_type(md))
> > +		dm_clear_request_based_queue(md);
> > +
> > +	return 0;
> > +}
> 
> These unregister/clear works shouldn't be needed if dm_setup_md_queue()
> is called only once as I mentioned above.

Indeed.  I'll get v3 of the patchset out with appropriate edits.

Thanks,
Mike




More information about the dm-devel mailing list