[dm-devel] [PATCH 4/6] dm-multipath: remove process_queued_ios()

Hannes Reinecke hare at suse.de
Mon Feb 3 11:39:55 UTC 2014


On 02/03/2014 12:30 PM, Junichi Nomura wrote:
> On 02/03/14 17:18, Hannes Reinecke wrote:
>> Doesn't serve any real purpose anymore; dm_table_run_queue()
>> will already move things to a workqueue, so we don't need
>> to do it ourselves.
>> We only need to take care to add a small delay when calling
>> __pg_init_all_paths() to move processing off to a workqueue;
>> pg_init_done() is run from an interrupt context and needs to
>> complete as fast as possible.
> 
> I think more explanation is needed for the patch description.
> As far as I understand, the change is based on the following reasoning:
> 
>   process_queued_ios() has served 3 functions:
>     1) select pg and pgpath if none is selected
>     2) start pg_init if requested
>     3) dispatch queued IOs when pg is ready
> 
>   Basically, a call to queue_work(process_queued_ios) can be replaced by
>   dm_table_run_queue(), which runs request queue and ends up calling
>   map_io(), which does 1), 2) and 3).
> 
Yes.

>   Exception is when !pg_ready() (= either pg_init is running or requested),
>   multipath_busy() prevents map_io() being called from request_fn.
> 
>   If pg_init is running, it should be ok as far as pg_init_done() does
>   the right thing when pg_init is completed. I.e. restart pg_init if
>   !pg_ready() or call dm_table_run_queue() to kick map_io().
> 
>   If pg_init is requested, we have to make sure the request is detected
>   and pg_init will be started.
>   pg_init is requested in 3 places:
>     a) __choose_pgpath() in map_io()
>     b) __choose_pgpath() in multipath_ioctl()
>     c) pg_init retry in pg_init_done()
>   a) is ok because map_io() calls __pg_init_all_paths(), which does 2).
>   b) needs a call to __pg_init_all_paths(), which does 2).
>   c) needs a call to __pg_init_all_paths(), which does 2).
> 
> 
> By writing the above, I found possible bugs related to 1):
> 
>> @@ -1217,9 +1185,11 @@ static void pg_init_done(void *data, int errors)
>>  
>>  	if (!m->pg_init_required)
>>  		m->queue_io = 0;
>> -
>> -	m->pg_init_delay_retry = delay_retry;
>> -	queue_work(kmultipathd, &m->process_queued_ios);
>> +	else {
>> +		m->pg_init_delay_retry = delay_retry;
>> +		__pg_init_all_paths(m, 50/HZ);
>> +		goto out;
>> +	}
>>  
>>  	/*
>>  	 * Wake up any thread waiting to suspend.
> 
> It is possible that m->current_pg is NULL.
> (E.g. pg_init failed for current_pgpath, bypass_pg() was called, etc.)
> __pg_init_all_paths() will cause oops in such a case.
> 
Ah. Right.

> So how about doing this in pg_init_done():
> 
> 	if (m->pg_init_required) {
> 		m->pg_init_delay_retry = delay_retry;
> 		if (__pg_init_all_paths(m))
> 			goto out;
> 	}
> 
> 	/* pg_init successfully completed */
> 	m->queue_io = 0;
> 
> and in __pg_init_all_paths(), do something like:
> 
> 	m->pg_init_required = 0;
> 	...
> 	if (!m->current_pg)
> 		return 0;
> 	...
> 	return m->pg_init_in_progress;
> 
> 
Hmm. That still wouldn't be doing the right thing.
'fail_path' in pg_init_done() might be setting current_pg to NULL,
but this doesn't mean that the entire path group is invalid.
I just means that this particular path is invalid, and we still
might need to retry pg_init for the other paths.

>> @@ -1593,8 +1563,13 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd,
>>  	if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT)
>>  		r = scsi_verify_blk_ioctl(NULL, cmd);
>>  
>> -	if (r == -ENOTCONN && !fatal_signal_pending(current))
>> -		queue_work(kmultipathd, &m->process_queued_ios);
>> +	if (r == -ENOTCONN && !fatal_signal_pending(current)) {
>> +		spin_lock_irqsave(&m->lock, flags);
>> +		if (m->current_pgpath && m->pg_init_required)
>> +			__pg_init_all_paths(m, 0);
>> +		spin_unlock_irqrestore(&m->lock, flags);
>> +		dm_table_run_md_queue_async(m->ti->table);
>> +	}
>>  
>>  	return r ? : __blkdev_driver_ioctl(bdev, mode, cmd, arg);
>>  }
> 
> Similarly, m->current_pgpath can be NULL here while pg_init_required.
> Then pg_init_required is left uncleared and all IOs in the queue will
> stall until somebody calls multipath_ioctl() to redo pg selection.
> 
Ok, correct. Will be fixing it up.

Thanks for the review.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		      zSeries & Storage
hare at suse.de			      +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)




More information about the dm-devel mailing list