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

block: get rid of QUEUE_FLAG_REENTER

We are currently using this flag to check whether it's safe
to call into ->request_fn(). If it is set, we punt to kblockd.
But we get a lot of false positives and excessive punts to
kblockd, which hurts performance.

The only real abuser of this infrastructure is SCSI. So export
the async queue run and convert SCSI over to use that. There's
room for improvement in that SCSI need not always use the async
call, but this fixes our performance issue and they can fix that
up in due time.

Signed-off-by: Jens Axboe <jaxboe@fusionio.com>

+20 -54
+2 -9
block/blk-core.c
··· 303 303 if (unlikely(blk_queue_stopped(q))) 304 304 return; 305 305 306 - /* 307 - * Only recurse once to avoid overrunning the stack, let the unplug 308 - * handling reinvoke the handler shortly if we already got there. 309 - */ 310 - if (!queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) { 311 - q->request_fn(q); 312 - queue_flag_clear(QUEUE_FLAG_REENTER, q); 313 - } else 314 - queue_delayed_work(kblockd_workqueue, &q->delay_work, 0); 306 + q->request_fn(q); 315 307 } 316 308 EXPORT_SYMBOL(__blk_run_queue); 317 309 ··· 320 328 if (likely(!blk_queue_stopped(q))) 321 329 queue_delayed_work(kblockd_workqueue, &q->delay_work, 0); 322 330 } 331 + EXPORT_SYMBOL(blk_run_queue_async); 323 332 324 333 /** 325 334 * blk_run_queue - run a single device queue
-1
block/blk.h
··· 22 22 void blk_delete_timer(struct request *); 23 23 void blk_add_timer(struct request *); 24 24 void __generic_unplug_device(struct request_queue *); 25 - void blk_run_queue_async(struct request_queue *q); 26 25 27 26 /* 28 27 * Internal atomic flags for request handling
+1 -16
drivers/scsi/scsi_lib.c
··· 411 411 list_splice_init(&shost->starved_list, &starved_list); 412 412 413 413 while (!list_empty(&starved_list)) { 414 - int flagset; 415 - 416 414 /* 417 415 * As long as shost is accepting commands and we have 418 416 * starved queues, call blk_run_queue. scsi_request_fn ··· 433 435 continue; 434 436 } 435 437 436 - spin_unlock(shost->host_lock); 437 - 438 - spin_lock(sdev->request_queue->queue_lock); 439 - flagset = test_bit(QUEUE_FLAG_REENTER, &q->queue_flags) && 440 - !test_bit(QUEUE_FLAG_REENTER, 441 - &sdev->request_queue->queue_flags); 442 - if (flagset) 443 - queue_flag_set(QUEUE_FLAG_REENTER, sdev->request_queue); 444 - __blk_run_queue(sdev->request_queue); 445 - if (flagset) 446 - queue_flag_clear(QUEUE_FLAG_REENTER, sdev->request_queue); 447 - spin_unlock(sdev->request_queue->queue_lock); 448 - 449 - spin_lock(shost->host_lock); 438 + blk_run_queue_async(sdev->request_queue); 450 439 } 451 440 /* put any unprocessed entries back */ 452 441 list_splice(&starved_list, &shost->starved_list);
+4 -15
drivers/scsi/scsi_transport_fc.c
··· 3816 3816 static void 3817 3817 fc_bsg_goose_queue(struct fc_rport *rport) 3818 3818 { 3819 - int flagset; 3820 - unsigned long flags; 3821 - 3822 3819 if (!rport->rqst_q) 3823 3820 return; 3824 3821 3822 + /* 3823 + * This get/put dance makes no sense 3824 + */ 3825 3825 get_device(&rport->dev); 3826 - 3827 - spin_lock_irqsave(rport->rqst_q->queue_lock, flags); 3828 - flagset = test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags) && 3829 - !test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags); 3830 - if (flagset) 3831 - queue_flag_set(QUEUE_FLAG_REENTER, rport->rqst_q); 3832 - __blk_run_queue(rport->rqst_q); 3833 - if (flagset) 3834 - queue_flag_clear(QUEUE_FLAG_REENTER, rport->rqst_q); 3835 - spin_unlock_irqrestore(rport->rqst_q->queue_lock, flags); 3836 - 3826 + blk_run_queue_async(rport->rqst_q); 3837 3827 put_device(&rport->dev); 3838 3828 } 3839 - 3840 3829 3841 3830 /** 3842 3831 * fc_bsg_rport_dispatch - process rport bsg requests and dispatch to LLDD
+13 -13
include/linux/blkdev.h
··· 388 388 #define QUEUE_FLAG_SYNCFULL 3 /* read queue has been filled */ 389 389 #define QUEUE_FLAG_ASYNCFULL 4 /* write queue has been filled */ 390 390 #define QUEUE_FLAG_DEAD 5 /* queue being torn down */ 391 - #define QUEUE_FLAG_REENTER 6 /* Re-entrancy avoidance */ 392 - #define QUEUE_FLAG_ELVSWITCH 7 /* don't use elevator, just do FIFO */ 393 - #define QUEUE_FLAG_BIDI 8 /* queue supports bidi requests */ 394 - #define QUEUE_FLAG_NOMERGES 9 /* disable merge attempts */ 395 - #define QUEUE_FLAG_SAME_COMP 10 /* force complete on same CPU */ 396 - #define QUEUE_FLAG_FAIL_IO 11 /* fake timeout */ 397 - #define QUEUE_FLAG_STACKABLE 12 /* supports request stacking */ 398 - #define QUEUE_FLAG_NONROT 13 /* non-rotational device (SSD) */ 391 + #define QUEUE_FLAG_ELVSWITCH 6 /* don't use elevator, just do FIFO */ 392 + #define QUEUE_FLAG_BIDI 7 /* queue supports bidi requests */ 393 + #define QUEUE_FLAG_NOMERGES 8 /* disable merge attempts */ 394 + #define QUEUE_FLAG_SAME_COMP 9 /* force complete on same CPU */ 395 + #define QUEUE_FLAG_FAIL_IO 10 /* fake timeout */ 396 + #define QUEUE_FLAG_STACKABLE 11 /* supports request stacking */ 397 + #define QUEUE_FLAG_NONROT 12 /* non-rotational device (SSD) */ 399 398 #define QUEUE_FLAG_VIRT QUEUE_FLAG_NONROT /* paravirt device */ 400 - #define QUEUE_FLAG_IO_STAT 15 /* do IO stats */ 401 - #define QUEUE_FLAG_DISCARD 16 /* supports DISCARD */ 402 - #define QUEUE_FLAG_NOXMERGES 17 /* No extended merges */ 403 - #define QUEUE_FLAG_ADD_RANDOM 18 /* Contributes to random pool */ 404 - #define QUEUE_FLAG_SECDISCARD 19 /* supports SECDISCARD */ 399 + #define QUEUE_FLAG_IO_STAT 13 /* do IO stats */ 400 + #define QUEUE_FLAG_DISCARD 14 /* supports DISCARD */ 401 + #define QUEUE_FLAG_NOXMERGES 15 /* No extended merges */ 402 + #define QUEUE_FLAG_ADD_RANDOM 16 /* Contributes to random pool */ 403 + #define QUEUE_FLAG_SECDISCARD 17 /* supports SECDISCARD */ 405 404 406 405 #define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \ 407 406 (1 << QUEUE_FLAG_STACKABLE) | \ ··· 698 699 extern void __blk_stop_queue(struct request_queue *q); 699 700 extern void __blk_run_queue(struct request_queue *q); 700 701 extern void blk_run_queue(struct request_queue *); 702 + extern void blk_run_queue_async(struct request_queue *q); 701 703 extern int blk_rq_map_user(struct request_queue *, struct request *, 702 704 struct rq_map_data *, void __user *, unsigned long, 703 705 gfp_t);