Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 109b8129 authored by NeilBrown's avatar NeilBrown Committed by Jens Axboe
Browse files

block: splice plug list to local context



If the request_fn ends up blocking, we could be re-entering
the plug flush. Since the list is protected by explicitly
not allowing schedule events, this isn't a terribly good idea.

Additionally, it can cause us to recurse. As request_fn called by
__blk_run_queue is allowed to 'schedule()' (after dropping the queue
lock of course), it is possible to get a recursive call:

 schedule -> blk_flush_plug -> __blk_finish_plug -> flush_plug_list
      -> __blk_run_queue -> request_fn -> schedule

We must make sure that the second schedule does not call into
blk_flush_plug again.  So instead of leaving the list of requests on
blk_plug->list, move them to a separate list leaving blk_plug->list
empty.

Signed-off-by: default avatarJens Axboe <jaxboe@fusionio.com>
parent 4263a2f1
Loading
Loading
Loading
Loading
+9 −5
Original line number Original line Diff line number Diff line
@@ -2673,19 +2673,24 @@ static void flush_plug_list(struct blk_plug *plug)
	struct request_queue *q;
	struct request_queue *q;
	unsigned long flags;
	unsigned long flags;
	struct request *rq;
	struct request *rq;
	LIST_HEAD(list);


	BUG_ON(plug->magic != PLUG_MAGIC);
	BUG_ON(plug->magic != PLUG_MAGIC);


	if (list_empty(&plug->list))
	if (list_empty(&plug->list))
		return;
		return;


	if (plug->should_sort)
	list_splice_init(&plug->list, &list);
		list_sort(NULL, &plug->list, plug_rq_cmp);

	if (plug->should_sort) {
		list_sort(NULL, &list, plug_rq_cmp);
		plug->should_sort = 0;
	}


	q = NULL;
	q = NULL;
	local_irq_save(flags);
	local_irq_save(flags);
	while (!list_empty(&plug->list)) {
	while (!list_empty(&list)) {
		rq = list_entry_rq(plug->list.next);
		rq = list_entry_rq(list.next);
		list_del_init(&rq->queuelist);
		list_del_init(&rq->queuelist);
		BUG_ON(!(rq->cmd_flags & REQ_ON_PLUG));
		BUG_ON(!(rq->cmd_flags & REQ_ON_PLUG));
		BUG_ON(!rq->q);
		BUG_ON(!rq->q);
@@ -2713,7 +2718,6 @@ static void flush_plug_list(struct blk_plug *plug)
		spin_unlock(q->queue_lock);
		spin_unlock(q->queue_lock);
	}
	}


	BUG_ON(!list_empty(&plug->list));
	local_irq_restore(flags);
	local_irq_restore(flags);
}
}