forked from mirrors/linux
		
	block: blk-flush shouldn't call directly into q->request_fn() __blk_run_queue()
blk-flush decomposes a flush into sequence of multiple requests. On completion of a request, the next one is queued; however, block layer must not implicitly call into q->request_fn() directly from completion path. This makes the queue behave unexpectedly when seen from the drivers and violates the assumption that q->request_fn() is called with process context + queue_lock. This patch makes blk-flush the following two changes to make sure q->request_fn() is not called directly from request completion path. - blk_flush_complete_seq_end_io() now asks __blk_run_queue() to always use kblockd instead of calling directly into q->request_fn(). - queue_next_fseq() uses ELEVATOR_INSERT_REQUEUE instead of ELEVATOR_INSERT_FRONT so that elv_insert() doesn't try to unplug the request queue directly. Reported by Jan in the following threads. http://thread.gmane.org/gmane.linux.ide/48778 http://thread.gmane.org/gmane.linux.ide/48786 stable: applicable to v2.6.37. Signed-off-by: Tejun Heo <tj@kernel.org> Reported-by: Jan Beulich <JBeulich@novell.com> Cc: "David S. Miller" <davem@davemloft.net> Cc: stable@kernel.org Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
This commit is contained in:
		
							parent
							
								
									1654e7411a
								
							
						
					
					
						commit
						255bb490c8
					
				
					 1 changed files with 5 additions and 3 deletions
				
			
		| 
						 | 
				
			
			@ -66,10 +66,12 @@ static void blk_flush_complete_seq_end_io(struct request_queue *q,
 | 
			
		|||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Moving a request silently to empty queue_head may stall the
 | 
			
		||||
	 * queue.  Kick the queue in those cases.
 | 
			
		||||
	 * queue.  Kick the queue in those cases.  This function is called
 | 
			
		||||
	 * from request completion path and calling directly into
 | 
			
		||||
	 * request_fn may confuse the driver.  Always use kblockd.
 | 
			
		||||
	 */
 | 
			
		||||
	if (was_empty && next_rq)
 | 
			
		||||
		__blk_run_queue(q, false);
 | 
			
		||||
		__blk_run_queue(q, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void pre_flush_end_io(struct request *rq, int error)
 | 
			
		||||
| 
						 | 
				
			
			@ -130,7 +132,7 @@ static struct request *queue_next_fseq(struct request_queue *q)
 | 
			
		|||
		BUG();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	elv_insert(q, rq, ELEVATOR_INSERT_FRONT);
 | 
			
		||||
	elv_insert(q, rq, ELEVATOR_INSERT_REQUEUE);
 | 
			
		||||
	return rq;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue