Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

block: Make blk_cleanup_queue() wait until request_fn finished

Some request_fn implementations, e.g. scsi_request_fn(), unlock
the queue lock internally. This may result in multiple threads
executing request_fn for the same queue simultaneously. Keep
track of the number of active request_fn calls and make sure that
blk_cleanup_queue() waits until all active request_fn invocations
have finished. A block driver may start cleaning up resources
needed by its request_fn as soon as blk_cleanup_queue() finished,
so blk_cleanup_queue() must wait for all outstanding request_fn
invocations to finish.

Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Reported-by: Chanho Min <chanho.min@lge.com>
Cc: James Bottomley <JBottomley@Parallels.com>
Cc: Mike Christie <michaelc@cs.wisc.edu>
Acked-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Bart Van Assche and committed by
Jens Axboe
24faf6f6 70460571

+16
+10
block/blk-core.c
··· 309 309 if (unlikely(blk_queue_dead(q))) 310 310 return; 311 311 312 + /* 313 + * Some request_fn implementations, e.g. scsi_request_fn(), unlock 314 + * the queue lock internally. As a result multiple threads may be 315 + * running such a request function concurrently. Keep track of the 316 + * number of active request_fn invocations such that blk_drain_queue() 317 + * can wait until all these request_fn calls have finished. 318 + */ 319 + q->request_fn_active++; 312 320 q->request_fn(q); 321 + q->request_fn_active--; 313 322 } 314 323 315 324 /** ··· 417 408 __blk_run_queue(q); 418 409 419 410 drain |= q->nr_rqs_elvpriv; 411 + drain |= q->request_fn_active; 420 412 421 413 /* 422 414 * Unfortunately, requests are queued at and tracked from
+6
include/linux/blkdev.h
··· 378 378 379 379 unsigned int nr_sorted; 380 380 unsigned int in_flight[2]; 381 + /* 382 + * Number of active block driver functions for which blk_drain_queue() 383 + * must wait. Must be incremented around functions that unlock the 384 + * queue_lock internally, e.g. scsi_request_fn(). 385 + */ 386 + unsigned int request_fn_active; 381 387 382 388 unsigned int rq_timeout; 383 389 struct timer_list timeout;