diff options
author | Christoph Hellwig <hch@lst.de> | 2014-01-22 08:49:41 -0500 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2014-07-25 07:39:00 -0400 |
commit | 7ae65c0f9646c29432b69580b80e08632e6cd813 (patch) | |
tree | 9b4cf362095370eeb5c42d21dc33746d0ba088bd | |
parent | cf68d334dd3a323624f6399dc807d34d8b816391 (diff) |
scsi: convert target_busy to an atomic_t
Avoid taking the host-wide host_lock to check the per-target queue limit.
Instead we do an atomic_inc_return early on to grab our slot in the queue,
and if necessary decrement it after finishing all checks.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Webb Scales <webbnh@hp.com>
Acked-by: Jens Axboe <axboe@kernel.dk>
Tested-by: Bart Van Assche <bvanassche@acm.org>
Tested-by: Robert Elliott <elliott@hp.com>
-rw-r--r-- | drivers/scsi/scsi_lib.c | 53 | ||||
-rw-r--r-- | include/scsi/scsi_device.h | 4 |
2 files changed, 34 insertions, 23 deletions
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 112c737884c3..0580711c2c57 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c | |||
@@ -294,7 +294,7 @@ void scsi_device_unbusy(struct scsi_device *sdev) | |||
294 | 294 | ||
295 | spin_lock_irqsave(shost->host_lock, flags); | 295 | spin_lock_irqsave(shost->host_lock, flags); |
296 | shost->host_busy--; | 296 | shost->host_busy--; |
297 | starget->target_busy--; | 297 | atomic_dec(&starget->target_busy); |
298 | if (unlikely(scsi_host_in_recovery(shost) && | 298 | if (unlikely(scsi_host_in_recovery(shost) && |
299 | (shost->host_failed || shost->host_eh_scheduled))) | 299 | (shost->host_failed || shost->host_eh_scheduled))) |
300 | scsi_eh_wakeup(shost); | 300 | scsi_eh_wakeup(shost); |
@@ -361,7 +361,7 @@ static inline int scsi_device_is_busy(struct scsi_device *sdev) | |||
361 | static inline int scsi_target_is_busy(struct scsi_target *starget) | 361 | static inline int scsi_target_is_busy(struct scsi_target *starget) |
362 | { | 362 | { |
363 | return ((starget->can_queue > 0 && | 363 | return ((starget->can_queue > 0 && |
364 | starget->target_busy >= starget->can_queue) || | 364 | atomic_read(&starget->target_busy) >= starget->can_queue) || |
365 | starget->target_blocked); | 365 | starget->target_blocked); |
366 | } | 366 | } |
367 | 367 | ||
@@ -1279,37 +1279,50 @@ static inline int scsi_target_queue_ready(struct Scsi_Host *shost, | |||
1279 | struct scsi_device *sdev) | 1279 | struct scsi_device *sdev) |
1280 | { | 1280 | { |
1281 | struct scsi_target *starget = scsi_target(sdev); | 1281 | struct scsi_target *starget = scsi_target(sdev); |
1282 | int ret = 0; | 1282 | unsigned int busy; |
1283 | 1283 | ||
1284 | spin_lock_irq(shost->host_lock); | ||
1285 | if (starget->single_lun) { | 1284 | if (starget->single_lun) { |
1285 | spin_lock_irq(shost->host_lock); | ||
1286 | if (starget->starget_sdev_user && | 1286 | if (starget->starget_sdev_user && |
1287 | starget->starget_sdev_user != sdev) | 1287 | starget->starget_sdev_user != sdev) { |
1288 | goto out; | 1288 | spin_unlock_irq(shost->host_lock); |
1289 | return 0; | ||
1290 | } | ||
1289 | starget->starget_sdev_user = sdev; | 1291 | starget->starget_sdev_user = sdev; |
1292 | spin_unlock_irq(shost->host_lock); | ||
1290 | } | 1293 | } |
1291 | 1294 | ||
1292 | if (starget->target_busy == 0 && starget->target_blocked) { | 1295 | busy = atomic_inc_return(&starget->target_busy) - 1; |
1296 | if (starget->target_blocked) { | ||
1297 | if (busy) | ||
1298 | goto starved; | ||
1299 | |||
1293 | /* | 1300 | /* |
1294 | * unblock after target_blocked iterates to zero | 1301 | * unblock after target_blocked iterates to zero |
1295 | */ | 1302 | */ |
1296 | if (--starget->target_blocked != 0) | 1303 | spin_lock_irq(shost->host_lock); |
1297 | goto out; | 1304 | if (--starget->target_blocked != 0) { |
1305 | spin_unlock_irq(shost->host_lock); | ||
1306 | goto out_dec; | ||
1307 | } | ||
1308 | spin_unlock_irq(shost->host_lock); | ||
1298 | 1309 | ||
1299 | SCSI_LOG_MLQUEUE(3, starget_printk(KERN_INFO, starget, | 1310 | SCSI_LOG_MLQUEUE(3, starget_printk(KERN_INFO, starget, |
1300 | "unblocking target at zero depth\n")); | 1311 | "unblocking target at zero depth\n")); |
1301 | } | 1312 | } |
1302 | 1313 | ||
1303 | if (scsi_target_is_busy(starget)) { | 1314 | if (starget->can_queue > 0 && busy >= starget->can_queue) |
1304 | list_move_tail(&sdev->starved_entry, &shost->starved_list); | 1315 | goto starved; |
1305 | goto out; | ||
1306 | } | ||
1307 | 1316 | ||
1308 | scsi_target(sdev)->target_busy++; | 1317 | return 1; |
1309 | ret = 1; | 1318 | |
1310 | out: | 1319 | starved: |
1320 | spin_lock_irq(shost->host_lock); | ||
1321 | list_move_tail(&sdev->starved_entry, &shost->starved_list); | ||
1311 | spin_unlock_irq(shost->host_lock); | 1322 | spin_unlock_irq(shost->host_lock); |
1312 | return ret; | 1323 | out_dec: |
1324 | atomic_dec(&starget->target_busy); | ||
1325 | return 0; | ||
1313 | } | 1326 | } |
1314 | 1327 | ||
1315 | /* | 1328 | /* |
@@ -1419,7 +1432,7 @@ static void scsi_kill_request(struct request *req, struct request_queue *q) | |||
1419 | spin_unlock(sdev->request_queue->queue_lock); | 1432 | spin_unlock(sdev->request_queue->queue_lock); |
1420 | spin_lock(shost->host_lock); | 1433 | spin_lock(shost->host_lock); |
1421 | shost->host_busy++; | 1434 | shost->host_busy++; |
1422 | starget->target_busy++; | 1435 | atomic_inc(&starget->target_busy); |
1423 | spin_unlock(shost->host_lock); | 1436 | spin_unlock(shost->host_lock); |
1424 | spin_lock(sdev->request_queue->queue_lock); | 1437 | spin_lock(sdev->request_queue->queue_lock); |
1425 | 1438 | ||
@@ -1589,9 +1602,7 @@ static void scsi_request_fn(struct request_queue *q) | |||
1589 | return; | 1602 | return; |
1590 | 1603 | ||
1591 | host_not_ready: | 1604 | host_not_ready: |
1592 | spin_lock_irq(shost->host_lock); | 1605 | atomic_dec(&scsi_target(sdev)->target_busy); |
1593 | scsi_target(sdev)->target_busy--; | ||
1594 | spin_unlock_irq(shost->host_lock); | ||
1595 | not_ready: | 1606 | not_ready: |
1596 | /* | 1607 | /* |
1597 | * lock q, handle tag, requeue req, and decrement device_busy. We | 1608 | * lock q, handle tag, requeue req, and decrement device_busy. We |
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 9aa38f7b303b..4e078b63a9e5 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h | |||
@@ -291,8 +291,8 @@ struct scsi_target { | |||
291 | unsigned int expecting_lun_change:1; /* A device has reported | 291 | unsigned int expecting_lun_change:1; /* A device has reported |
292 | * a 3F/0E UA, other devices on | 292 | * a 3F/0E UA, other devices on |
293 | * the same target will also. */ | 293 | * the same target will also. */ |
294 | /* commands actually active on LLD. protected by host lock. */ | 294 | /* commands actually active on LLD. */ |
295 | unsigned int target_busy; | 295 | atomic_t target_busy; |
296 | /* | 296 | /* |
297 | * LLDs should set this in the slave_alloc host template callout. | 297 | * LLDs should set this in the slave_alloc host template callout. |
298 | * If set to zero then there is not limit. | 298 | * If set to zero then there is not limit. |