Commit bd87b589 authored by Tejun Heo's avatar Tejun Heo Committed by Jens Axboe

block: drop @tsk from attempt_plug_merge() and explain sync rules

attempt_plug_merge() accesses elevator without holding queue_lock and
may call into ->elevator_bio_merge_fn().  The elvator is guaranteed to
be valid because it's accessed iff the plugged list has requests and
elevator is never exited with live requests, so as long as the
elevator method can deal with unlocked access, this is safe.

Explain the sync rules around attempt_plug_merge() and drop the
unnecessary @tsk parameter.

This patch doesn't introduce any functional change.
Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent da8303c6
...@@ -1203,18 +1203,32 @@ static bool bio_attempt_front_merge(struct request_queue *q, ...@@ -1203,18 +1203,32 @@ static bool bio_attempt_front_merge(struct request_queue *q,
return true; return true;
} }
/* /**
* Attempts to merge with the plugged list in the current process. Returns * attempt_plug_merge - try to merge with %current's plugged list
* true if merge was successful, otherwise false. * @q: request_queue new bio is being queued at
* @bio: new bio being queued
* @request_count: out parameter for number of traversed plugged requests
*
* Determine whether @bio being queued on @q can be merged with a request
* on %current's plugged list. Returns %true if merge was successful,
* otherwise %false.
*
* This function is called without @q->queue_lock; however, elevator is
* accessed iff there already are requests on the plugged list which in
* turn guarantees validity of the elevator.
*
* Note that, on successful merge, elevator operation
* elevator_bio_merged_fn() will be called without queue lock. Elevator
* must be ready for this.
*/ */
static bool attempt_plug_merge(struct task_struct *tsk, struct request_queue *q, static bool attempt_plug_merge(struct request_queue *q, struct bio *bio,
struct bio *bio, unsigned int *request_count) unsigned int *request_count)
{ {
struct blk_plug *plug; struct blk_plug *plug;
struct request *rq; struct request *rq;
bool ret = false; bool ret = false;
plug = tsk->plug; plug = current->plug;
if (!plug) if (!plug)
goto out; goto out;
*request_count = 0; *request_count = 0;
...@@ -1282,7 +1296,7 @@ void blk_queue_bio(struct request_queue *q, struct bio *bio) ...@@ -1282,7 +1296,7 @@ void blk_queue_bio(struct request_queue *q, struct bio *bio)
* Check if we can merge with the plugged list before grabbing * Check if we can merge with the plugged list before grabbing
* any locks. * any locks.
*/ */
if (attempt_plug_merge(current, q, bio, &request_count)) if (attempt_plug_merge(q, bio, &request_count))
return; return;
spin_lock_irq(q->queue_lock); spin_lock_irq(q->queue_lock);
......
...@@ -38,6 +38,12 @@ struct elevator_ops ...@@ -38,6 +38,12 @@ struct elevator_ops
elevator_merged_fn *elevator_merged_fn; elevator_merged_fn *elevator_merged_fn;
elevator_merge_req_fn *elevator_merge_req_fn; elevator_merge_req_fn *elevator_merge_req_fn;
elevator_allow_merge_fn *elevator_allow_merge_fn; elevator_allow_merge_fn *elevator_allow_merge_fn;
/*
* Used for both plugged list and elevator merging and in the
* former case called without queue_lock. Read comment on top of
* attempt_plug_merge() for details.
*/
elevator_bio_merged_fn *elevator_bio_merged_fn; elevator_bio_merged_fn *elevator_bio_merged_fn;
elevator_dispatch_fn *elevator_dispatch_fn; elevator_dispatch_fn *elevator_dispatch_fn;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment