Commit 826a70a08b1210bbfdbda812ab43eb986e25b5c2
Committed by
Jens Axboe
1 parent
e4f36b249b
SCSI: don't get target/host busy_count in scsi_mq_get_budget()
It is very expensive to atomic_inc/atomic_dec the host wide counter of host->busy_count, and it should have been avoided via blk-mq's mechanism of getting driver tag, which uses the more efficient way of sbitmap queue. Also we don't check atomic_read(&sdev->device_busy) in scsi_mq_get_budget() and don't run queue if the counter becomes zero, so IO hang may be caused if all requests are completed just before the current SCSI device is added to shost->starved_list. Fixes: 0df21c86bdbf(scsi: implement .get_budget and .put_budget for blk-mq) Reported-by: Bart Van Assche <bart.vanassche@wdc.com> Signed-off-by: Ming Lei <ming.lei@redhat.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
Showing 1 changed file with 13 additions and 16 deletions Side-by-side Diff
drivers/scsi/scsi_lib.c
... | ... | @@ -1950,11 +1950,7 @@ |
1950 | 1950 | { |
1951 | 1951 | struct request_queue *q = hctx->queue; |
1952 | 1952 | struct scsi_device *sdev = q->queuedata; |
1953 | - struct Scsi_Host *shost = sdev->host; | |
1954 | 1953 | |
1955 | - atomic_dec(&shost->host_busy); | |
1956 | - if (scsi_target(sdev)->can_queue > 0) | |
1957 | - atomic_dec(&scsi_target(sdev)->target_busy); | |
1958 | 1954 | atomic_dec(&sdev->device_busy); |
1959 | 1955 | put_device(&sdev->sdev_gendev); |
1960 | 1956 | } |
... | ... | @@ -1963,7 +1959,6 @@ |
1963 | 1959 | { |
1964 | 1960 | struct request_queue *q = hctx->queue; |
1965 | 1961 | struct scsi_device *sdev = q->queuedata; |
1966 | - struct Scsi_Host *shost = sdev->host; | |
1967 | 1962 | blk_status_t ret; |
1968 | 1963 | |
1969 | 1964 | ret = prep_to_mq(scsi_prep_state_check(sdev, NULL)); |
1970 | 1965 | |
... | ... | @@ -1974,18 +1969,9 @@ |
1974 | 1969 | goto out; |
1975 | 1970 | if (!scsi_dev_queue_ready(q, sdev)) |
1976 | 1971 | goto out_put_device; |
1977 | - if (!scsi_target_queue_ready(shost, sdev)) | |
1978 | - goto out_dec_device_busy; | |
1979 | - if (!scsi_host_queue_ready(q, shost, sdev)) | |
1980 | - goto out_dec_target_busy; | |
1981 | 1972 | |
1982 | 1973 | return BLK_STS_OK; |
1983 | 1974 | |
1984 | -out_dec_target_busy: | |
1985 | - if (scsi_target(sdev)->can_queue > 0) | |
1986 | - atomic_dec(&scsi_target(sdev)->target_busy); | |
1987 | -out_dec_device_busy: | |
1988 | - atomic_dec(&sdev->device_busy); | |
1989 | 1975 | out_put_device: |
1990 | 1976 | put_device(&sdev->sdev_gendev); |
1991 | 1977 | out: |
... | ... | @@ -1998,6 +1984,7 @@ |
1998 | 1984 | struct request *req = bd->rq; |
1999 | 1985 | struct request_queue *q = req->q; |
2000 | 1986 | struct scsi_device *sdev = q->queuedata; |
1987 | + struct Scsi_Host *shost = sdev->host; | |
2001 | 1988 | struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(req); |
2002 | 1989 | blk_status_t ret; |
2003 | 1990 | int reason; |
2004 | 1991 | |
... | ... | @@ -2007,10 +1994,15 @@ |
2007 | 1994 | goto out_put_budget; |
2008 | 1995 | |
2009 | 1996 | ret = BLK_STS_RESOURCE; |
1997 | + if (!scsi_target_queue_ready(shost, sdev)) | |
1998 | + goto out_put_budget; | |
1999 | + if (!scsi_host_queue_ready(q, shost, sdev)) | |
2000 | + goto out_dec_target_busy; | |
2001 | + | |
2010 | 2002 | if (!(req->rq_flags & RQF_DONTPREP)) { |
2011 | 2003 | ret = prep_to_mq(scsi_mq_prep_fn(req)); |
2012 | 2004 | if (ret != BLK_STS_OK) |
2013 | - goto out_put_budget; | |
2005 | + goto out_dec_host_busy; | |
2014 | 2006 | req->rq_flags |= RQF_DONTPREP; |
2015 | 2007 | } else { |
2016 | 2008 | blk_mq_start_request(req); |
2017 | 2009 | |
... | ... | @@ -2028,11 +2020,16 @@ |
2028 | 2020 | if (reason) { |
2029 | 2021 | scsi_set_blocked(cmd, reason); |
2030 | 2022 | ret = BLK_STS_RESOURCE; |
2031 | - goto out_put_budget; | |
2023 | + goto out_dec_host_busy; | |
2032 | 2024 | } |
2033 | 2025 | |
2034 | 2026 | return BLK_STS_OK; |
2035 | 2027 | |
2028 | +out_dec_host_busy: | |
2029 | + atomic_dec(&shost->host_busy); | |
2030 | +out_dec_target_busy: | |
2031 | + if (scsi_target(sdev)->can_queue > 0) | |
2032 | + atomic_dec(&scsi_target(sdev)->target_busy); | |
2036 | 2033 | out_put_budget: |
2037 | 2034 | scsi_mq_put_budget(hctx); |
2038 | 2035 | switch (ret) { |