aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2014-01-22 08:49:41 -0500
committerChristoph Hellwig <hch@lst.de>2014-07-25 07:39:00 -0400
commit7ae65c0f9646c29432b69580b80e08632e6cd813 (patch)
tree9b4cf362095370eeb5c42d21dc33746d0ba088bd
parentcf68d334dd3a323624f6399dc807d34d8b816391 (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.c53
-rw-r--r--include/scsi/scsi_device.h4
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)
361static inline int scsi_target_is_busy(struct scsi_target *starget) 361static 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
1310out: 1319starved:
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; 1323out_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.