diff options
| author | Ming Lei <ming.lei@redhat.com> | 2017-11-03 21:55:34 -0400 |
|---|---|---|
| committer | Jens Axboe <axboe@kernel.dk> | 2017-11-04 10:19:25 -0400 |
| commit | 826a70a08b1210bbfdbda812ab43eb986e25b5c2 (patch) | |
| tree | 34ffcdb1ac15fef880c93219cc4f5df4fe1785c8 /drivers/scsi/scsi_lib.c | |
| parent | e4f36b249b4d4e7599f1cf0c8fb50f196e52677e (diff) | |
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>
Diffstat (limited to 'drivers/scsi/scsi_lib.c')
| -rw-r--r-- | drivers/scsi/scsi_lib.c | 29 |
1 files changed, 13 insertions, 16 deletions
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 6f10afaca25b..22a7e4c47207 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c | |||
| @@ -1950,11 +1950,7 @@ static void scsi_mq_put_budget(struct blk_mq_hw_ctx *hctx) | |||
| 1950 | { | 1950 | { |
| 1951 | struct request_queue *q = hctx->queue; | 1951 | struct request_queue *q = hctx->queue; |
| 1952 | struct scsi_device *sdev = q->queuedata; | 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 | atomic_dec(&sdev->device_busy); | 1954 | atomic_dec(&sdev->device_busy); |
| 1959 | put_device(&sdev->sdev_gendev); | 1955 | put_device(&sdev->sdev_gendev); |
| 1960 | } | 1956 | } |
| @@ -1963,7 +1959,6 @@ static blk_status_t scsi_mq_get_budget(struct blk_mq_hw_ctx *hctx) | |||
| 1963 | { | 1959 | { |
| 1964 | struct request_queue *q = hctx->queue; | 1960 | struct request_queue *q = hctx->queue; |
| 1965 | struct scsi_device *sdev = q->queuedata; | 1961 | struct scsi_device *sdev = q->queuedata; |
| 1966 | struct Scsi_Host *shost = sdev->host; | ||
| 1967 | blk_status_t ret; | 1962 | blk_status_t ret; |
| 1968 | 1963 | ||
| 1969 | ret = prep_to_mq(scsi_prep_state_check(sdev, NULL)); | 1964 | ret = prep_to_mq(scsi_prep_state_check(sdev, NULL)); |
| @@ -1974,18 +1969,9 @@ static blk_status_t scsi_mq_get_budget(struct blk_mq_hw_ctx *hctx) | |||
| 1974 | goto out; | 1969 | goto out; |
| 1975 | if (!scsi_dev_queue_ready(q, sdev)) | 1970 | if (!scsi_dev_queue_ready(q, sdev)) |
| 1976 | goto out_put_device; | 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 | return BLK_STS_OK; | 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 | out_put_device: | 1975 | out_put_device: |
| 1990 | put_device(&sdev->sdev_gendev); | 1976 | put_device(&sdev->sdev_gendev); |
| 1991 | out: | 1977 | out: |
| @@ -1998,6 +1984,7 @@ static blk_status_t scsi_queue_rq(struct blk_mq_hw_ctx *hctx, | |||
| 1998 | struct request *req = bd->rq; | 1984 | struct request *req = bd->rq; |
| 1999 | struct request_queue *q = req->q; | 1985 | struct request_queue *q = req->q; |
| 2000 | struct scsi_device *sdev = q->queuedata; | 1986 | struct scsi_device *sdev = q->queuedata; |
| 1987 | struct Scsi_Host *shost = sdev->host; | ||
| 2001 | struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(req); | 1988 | struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(req); |
| 2002 | blk_status_t ret; | 1989 | blk_status_t ret; |
| 2003 | int reason; | 1990 | int reason; |
| @@ -2007,10 +1994,15 @@ static blk_status_t scsi_queue_rq(struct blk_mq_hw_ctx *hctx, | |||
| 2007 | goto out_put_budget; | 1994 | goto out_put_budget; |
| 2008 | 1995 | ||
| 2009 | ret = BLK_STS_RESOURCE; | 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 | if (!(req->rq_flags & RQF_DONTPREP)) { | 2002 | if (!(req->rq_flags & RQF_DONTPREP)) { |
| 2011 | ret = prep_to_mq(scsi_mq_prep_fn(req)); | 2003 | ret = prep_to_mq(scsi_mq_prep_fn(req)); |
| 2012 | if (ret != BLK_STS_OK) | 2004 | if (ret != BLK_STS_OK) |
| 2013 | goto out_put_budget; | 2005 | goto out_dec_host_busy; |
| 2014 | req->rq_flags |= RQF_DONTPREP; | 2006 | req->rq_flags |= RQF_DONTPREP; |
| 2015 | } else { | 2007 | } else { |
| 2016 | blk_mq_start_request(req); | 2008 | blk_mq_start_request(req); |
| @@ -2028,11 +2020,16 @@ static blk_status_t scsi_queue_rq(struct blk_mq_hw_ctx *hctx, | |||
| 2028 | if (reason) { | 2020 | if (reason) { |
| 2029 | scsi_set_blocked(cmd, reason); | 2021 | scsi_set_blocked(cmd, reason); |
| 2030 | ret = BLK_STS_RESOURCE; | 2022 | ret = BLK_STS_RESOURCE; |
| 2031 | goto out_put_budget; | 2023 | goto out_dec_host_busy; |
| 2032 | } | 2024 | } |
| 2033 | 2025 | ||
| 2034 | return BLK_STS_OK; | 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 | out_put_budget: | 2033 | out_put_budget: |
| 2037 | scsi_mq_put_budget(hctx); | 2034 | scsi_mq_put_budget(hctx); |
| 2038 | switch (ret) { | 2035 | switch (ret) { |
