aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2014-01-22 09:29:29 -0500
committerChristoph Hellwig <hch@lst.de>2014-07-25 07:43:43 -0400
commit74665016086615bbaa3fa6f83af410a0a4e029ee (patch)
tree9f9d8a692bec91dce69fd303eeedf16c35b41ac6
parent7ae65c0f9646c29432b69580b80e08632e6cd813 (diff)
scsi: convert host_busy to atomic_t
Avoid taking the host-wide host_lock to check the per-host 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/advansys.c4
-rw-r--r--drivers/scsi/libiscsi.c4
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c5
-rw-r--r--drivers/scsi/qlogicpti.c2
-rw-r--r--drivers/scsi/scsi.c2
-rw-r--r--drivers/scsi/scsi_error.c7
-rw-r--r--drivers/scsi/scsi_lib.c74
-rw-r--r--drivers/scsi/scsi_sysfs.c9
-rw-r--r--include/scsi/scsi_host.h10
9 files changed, 69 insertions, 48 deletions
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index e716d0aef194..43761c1c46f0 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -2512,7 +2512,7 @@ static void asc_prt_scsi_host(struct Scsi_Host *s)
2512 2512
2513 printk("Scsi_Host at addr 0x%p, device %s\n", s, dev_name(boardp->dev)); 2513 printk("Scsi_Host at addr 0x%p, device %s\n", s, dev_name(boardp->dev));
2514 printk(" host_busy %u, host_no %d,\n", 2514 printk(" host_busy %u, host_no %d,\n",
2515 s->host_busy, s->host_no); 2515 atomic_read(&s->host_busy), s->host_no);
2516 2516
2517 printk(" base 0x%lx, io_port 0x%lx, irq %d,\n", 2517 printk(" base 0x%lx, io_port 0x%lx, irq %d,\n",
2518 (ulong)s->base, (ulong)s->io_port, boardp->irq); 2518 (ulong)s->base, (ulong)s->io_port, boardp->irq);
@@ -3346,7 +3346,7 @@ static void asc_prt_driver_conf(struct seq_file *m, struct Scsi_Host *shost)
3346 3346
3347 seq_printf(m, 3347 seq_printf(m,
3348 " host_busy %u, max_id %u, max_lun %llu, max_channel %u\n", 3348 " host_busy %u, max_id %u, max_lun %llu, max_channel %u\n",
3349 shost->host_busy, shost->max_id, 3349 atomic_read(&shost->host_busy), shost->max_id,
3350 shost->max_lun, shost->max_channel); 3350 shost->max_lun, shost->max_channel);
3351 3351
3352 seq_printf(m, 3352 seq_printf(m,
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index f2db82beb646..f9f3a1224dfa 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -2971,7 +2971,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
2971 */ 2971 */
2972 for (;;) { 2972 for (;;) {
2973 spin_lock_irqsave(session->host->host_lock, flags); 2973 spin_lock_irqsave(session->host->host_lock, flags);
2974 if (!session->host->host_busy) { /* OK for ERL == 0 */ 2974 if (!atomic_read(&session->host->host_busy)) { /* OK for ERL == 0 */
2975 spin_unlock_irqrestore(session->host->host_lock, flags); 2975 spin_unlock_irqrestore(session->host->host_lock, flags);
2976 break; 2976 break;
2977 } 2977 }
@@ -2979,7 +2979,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
2979 msleep_interruptible(500); 2979 msleep_interruptible(500);
2980 iscsi_conn_printk(KERN_INFO, conn, "iscsi conn_destroy(): " 2980 iscsi_conn_printk(KERN_INFO, conn, "iscsi conn_destroy(): "
2981 "host_busy %d host_failed %d\n", 2981 "host_busy %d host_failed %d\n",
2982 session->host->host_busy, 2982 atomic_read(&session->host->host_busy),
2983 session->host->host_failed); 2983 session->host->host_failed);
2984 /* 2984 /*
2985 * force eh_abort() to unblock 2985 * force eh_abort() to unblock
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index 7d02a19419a7..24e477d2ea70 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -813,7 +813,7 @@ retry:
813 spin_unlock_irq(shost->host_lock); 813 spin_unlock_irq(shost->host_lock);
814 814
815 SAS_DPRINTK("Enter %s busy: %d failed: %d\n", 815 SAS_DPRINTK("Enter %s busy: %d failed: %d\n",
816 __func__, shost->host_busy, shost->host_failed); 816 __func__, atomic_read(&shost->host_busy), shost->host_failed);
817 /* 817 /*
818 * Deal with commands that still have SAS tasks (i.e. they didn't 818 * Deal with commands that still have SAS tasks (i.e. they didn't
819 * complete via the normal sas_task completion mechanism), 819 * complete via the normal sas_task completion mechanism),
@@ -858,7 +858,8 @@ out:
858 goto retry; 858 goto retry;
859 859
860 SAS_DPRINTK("--- Exit %s: busy: %d failed: %d tries: %d\n", 860 SAS_DPRINTK("--- Exit %s: busy: %d failed: %d tries: %d\n",
861 __func__, shost->host_busy, shost->host_failed, tries); 861 __func__, atomic_read(&shost->host_busy),
862 shost->host_failed, tries);
862} 863}
863 864
864enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd) 865enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index 6d48d30bed05..740ae495aa77 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -959,7 +959,7 @@ static inline void update_can_queue(struct Scsi_Host *host, u_int in_ptr, u_int
959 /* Temporary workaround until bug is found and fixed (one bug has been found 959 /* Temporary workaround until bug is found and fixed (one bug has been found
960 already, but fixing it makes things even worse) -jj */ 960 already, but fixing it makes things even worse) -jj */
961 int num_free = QLOGICPTI_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr) - 64; 961 int num_free = QLOGICPTI_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr) - 64;
962 host->can_queue = host->host_busy + num_free; 962 host->can_queue = atomic_read(&host->host_busy) + num_free;
963 host->sg_tablesize = QLOGICPTI_MAX_SG(num_free); 963 host->sg_tablesize = QLOGICPTI_MAX_SG(num_free);
964} 964}
965 965
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 6200a2615436..21fb97b01dd6 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -600,7 +600,7 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
600 if (level > 3) 600 if (level > 3)
601 scmd_printk(KERN_INFO, cmd, 601 scmd_printk(KERN_INFO, cmd,
602 "scsi host busy %d failed %d\n", 602 "scsi host busy %d failed %d\n",
603 cmd->device->host->host_busy, 603 atomic_read(&cmd->device->host->host_busy),
604 cmd->device->host->host_failed); 604 cmd->device->host->host_failed);
605 } 605 }
606 } 606 }
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index e4a532463f9a..5db8454474ee 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -59,7 +59,7 @@ static int scsi_try_to_abort_cmd(struct scsi_host_template *,
59/* called with shost->host_lock held */ 59/* called with shost->host_lock held */
60void scsi_eh_wakeup(struct Scsi_Host *shost) 60void scsi_eh_wakeup(struct Scsi_Host *shost)
61{ 61{
62 if (shost->host_busy == shost->host_failed) { 62 if (atomic_read(&shost->host_busy) == shost->host_failed) {
63 trace_scsi_eh_wakeup(shost); 63 trace_scsi_eh_wakeup(shost);
64 wake_up_process(shost->ehandler); 64 wake_up_process(shost->ehandler);
65 SCSI_LOG_ERROR_RECOVERY(5, shost_printk(KERN_INFO, shost, 65 SCSI_LOG_ERROR_RECOVERY(5, shost_printk(KERN_INFO, shost,
@@ -2164,7 +2164,7 @@ int scsi_error_handler(void *data)
2164 while (!kthread_should_stop()) { 2164 while (!kthread_should_stop()) {
2165 set_current_state(TASK_INTERRUPTIBLE); 2165 set_current_state(TASK_INTERRUPTIBLE);
2166 if ((shost->host_failed == 0 && shost->host_eh_scheduled == 0) || 2166 if ((shost->host_failed == 0 && shost->host_eh_scheduled == 0) ||
2167 shost->host_failed != shost->host_busy) { 2167 shost->host_failed != atomic_read(&shost->host_busy)) {
2168 SCSI_LOG_ERROR_RECOVERY(1, 2168 SCSI_LOG_ERROR_RECOVERY(1,
2169 shost_printk(KERN_INFO, shost, 2169 shost_printk(KERN_INFO, shost,
2170 "scsi_eh_%d: sleeping\n", 2170 "scsi_eh_%d: sleeping\n",
@@ -2178,7 +2178,8 @@ int scsi_error_handler(void *data)
2178 shost_printk(KERN_INFO, shost, 2178 shost_printk(KERN_INFO, shost,
2179 "scsi_eh_%d: waking up %d/%d/%d\n", 2179 "scsi_eh_%d: waking up %d/%d/%d\n",
2180 shost->host_no, shost->host_eh_scheduled, 2180 shost->host_no, shost->host_eh_scheduled,
2181 shost->host_failed, shost->host_busy)); 2181 shost->host_failed,
2182 atomic_read(&shost->host_busy)));
2182 2183
2183 /* 2184 /*
2184 * We have a host that is failing for some reason. Figure out 2185 * We have a host that is failing for some reason. Figure out
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 0580711c2c57..d0bd7e0ab7a8 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -292,14 +292,17 @@ void scsi_device_unbusy(struct scsi_device *sdev)
292 struct scsi_target *starget = scsi_target(sdev); 292 struct scsi_target *starget = scsi_target(sdev);
293 unsigned long flags; 293 unsigned long flags;
294 294
295 spin_lock_irqsave(shost->host_lock, flags); 295 atomic_dec(&shost->host_busy);
296 shost->host_busy--;
297 atomic_dec(&starget->target_busy); 296 atomic_dec(&starget->target_busy);
297
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 spin_lock_irqsave(shost->host_lock, flags);
300 scsi_eh_wakeup(shost); 301 scsi_eh_wakeup(shost);
301 spin_unlock(shost->host_lock); 302 spin_unlock_irqrestore(shost->host_lock, flags);
302 spin_lock(sdev->request_queue->queue_lock); 303 }
304
305 spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
303 sdev->device_busy--; 306 sdev->device_busy--;
304 spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); 307 spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
305} 308}
@@ -367,7 +370,8 @@ static inline int scsi_target_is_busy(struct scsi_target *starget)
367 370
368static inline int scsi_host_is_busy(struct Scsi_Host *shost) 371static inline int scsi_host_is_busy(struct Scsi_Host *shost)
369{ 372{
370 if ((shost->can_queue > 0 && shost->host_busy >= shost->can_queue) || 373 if ((shost->can_queue > 0 &&
374 atomic_read(&shost->host_busy) >= shost->can_queue) ||
371 shost->host_blocked || shost->host_self_blocked) 375 shost->host_blocked || shost->host_self_blocked)
372 return 1; 376 return 1;
373 377
@@ -1334,38 +1338,54 @@ static inline int scsi_host_queue_ready(struct request_queue *q,
1334 struct Scsi_Host *shost, 1338 struct Scsi_Host *shost,
1335 struct scsi_device *sdev) 1339 struct scsi_device *sdev)
1336{ 1340{
1337 int ret = 0; 1341 unsigned int busy;
1338
1339 spin_lock_irq(shost->host_lock);
1340 1342
1341 if (scsi_host_in_recovery(shost)) 1343 if (scsi_host_in_recovery(shost))
1342 goto out; 1344 return 0;
1343 if (shost->host_busy == 0 && shost->host_blocked) { 1345
1346 busy = atomic_inc_return(&shost->host_busy) - 1;
1347 if (shost->host_blocked) {
1348 if (busy)
1349 goto starved;
1350
1344 /* 1351 /*
1345 * unblock after host_blocked iterates to zero 1352 * unblock after host_blocked iterates to zero
1346 */ 1353 */
1347 if (--shost->host_blocked != 0) 1354 spin_lock_irq(shost->host_lock);
1348 goto out; 1355 if (--shost->host_blocked != 0) {
1356 spin_unlock_irq(shost->host_lock);
1357 goto out_dec;
1358 }
1359 spin_unlock_irq(shost->host_lock);
1349 1360
1350 SCSI_LOG_MLQUEUE(3, 1361 SCSI_LOG_MLQUEUE(3,
1351 shost_printk(KERN_INFO, shost, 1362 shost_printk(KERN_INFO, shost,
1352 "unblocking host at zero depth\n")); 1363 "unblocking host at zero depth\n"));
1353 } 1364 }
1354 if (scsi_host_is_busy(shost)) { 1365
1355 if (list_empty(&sdev->starved_entry)) 1366 if (shost->can_queue > 0 && busy >= shost->can_queue)
1356 list_add_tail(&sdev->starved_entry, &shost->starved_list); 1367 goto starved;
1357 goto out; 1368 if (shost->host_self_blocked)
1358 } 1369 goto starved;
1359 1370
1360 /* We're OK to process the command, so we can't be starved */ 1371 /* We're OK to process the command, so we can't be starved */
1361 if (!list_empty(&sdev->starved_entry)) 1372 if (!list_empty(&sdev->starved_entry)) {
1362 list_del_init(&sdev->starved_entry); 1373 spin_lock_irq(shost->host_lock);
1374 if (!list_empty(&sdev->starved_entry))
1375 list_del_init(&sdev->starved_entry);
1376 spin_unlock_irq(shost->host_lock);
1377 }
1363 1378
1364 shost->host_busy++; 1379 return 1;
1365 ret = 1; 1380
1366out: 1381starved:
1382 spin_lock_irq(shost->host_lock);
1383 if (list_empty(&sdev->starved_entry))
1384 list_add_tail(&sdev->starved_entry, &shost->starved_list);
1367 spin_unlock_irq(shost->host_lock); 1385 spin_unlock_irq(shost->host_lock);
1368 return ret; 1386out_dec:
1387 atomic_dec(&shost->host_busy);
1388 return 0;
1369} 1389}
1370 1390
1371/* 1391/*
@@ -1429,12 +1449,8 @@ static void scsi_kill_request(struct request *req, struct request_queue *q)
1429 * with the locks as normal issue path does. 1449 * with the locks as normal issue path does.
1430 */ 1450 */
1431 sdev->device_busy++; 1451 sdev->device_busy++;
1432 spin_unlock(sdev->request_queue->queue_lock); 1452 atomic_inc(&shost->host_busy);
1433 spin_lock(shost->host_lock);
1434 shost->host_busy++;
1435 atomic_inc(&starget->target_busy); 1453 atomic_inc(&starget->target_busy);
1436 spin_unlock(shost->host_lock);
1437 spin_lock(sdev->request_queue->queue_lock);
1438 1454
1439 blk_complete_request(req); 1455 blk_complete_request(req);
1440} 1456}
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 5f36788705ba..de57b8bca7be 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -334,7 +334,6 @@ store_shost_eh_deadline(struct device *dev, struct device_attribute *attr,
334static DEVICE_ATTR(eh_deadline, S_IRUGO | S_IWUSR, show_shost_eh_deadline, store_shost_eh_deadline); 334static DEVICE_ATTR(eh_deadline, S_IRUGO | S_IWUSR, show_shost_eh_deadline, store_shost_eh_deadline);
335 335
336shost_rd_attr(unique_id, "%u\n"); 336shost_rd_attr(unique_id, "%u\n");
337shost_rd_attr(host_busy, "%hu\n");
338shost_rd_attr(cmd_per_lun, "%hd\n"); 337shost_rd_attr(cmd_per_lun, "%hd\n");
339shost_rd_attr(can_queue, "%hd\n"); 338shost_rd_attr(can_queue, "%hd\n");
340shost_rd_attr(sg_tablesize, "%hu\n"); 339shost_rd_attr(sg_tablesize, "%hu\n");
@@ -344,6 +343,14 @@ shost_rd_attr(prot_capabilities, "%u\n");
344shost_rd_attr(prot_guard_type, "%hd\n"); 343shost_rd_attr(prot_guard_type, "%hd\n");
345shost_rd_attr2(proc_name, hostt->proc_name, "%s\n"); 344shost_rd_attr2(proc_name, hostt->proc_name, "%s\n");
346 345
346static ssize_t
347show_host_busy(struct device *dev, struct device_attribute *attr, char *buf)
348{
349 struct Scsi_Host *shost = class_to_shost(dev);
350 return snprintf(buf, 20, "%d\n", atomic_read(&shost->host_busy));
351}
352static DEVICE_ATTR(host_busy, S_IRUGO, show_host_busy, NULL);
353
347static struct attribute *scsi_sysfs_shost_attrs[] = { 354static struct attribute *scsi_sysfs_shost_attrs[] = {
348 &dev_attr_unique_id.attr, 355 &dev_attr_unique_id.attr,
349 &dev_attr_host_busy.attr, 356 &dev_attr_host_busy.attr,
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index b2bc5198b7fb..51f7911b1cbb 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -582,13 +582,9 @@ struct Scsi_Host {
582 */ 582 */
583 struct blk_queue_tag *bqt; 583 struct blk_queue_tag *bqt;
584 584
585 /* 585 atomic_t host_busy; /* commands actually active on low-level */
586 * The following two fields are protected with host_lock; 586 unsigned int host_failed; /* commands that failed.
587 * however, eh routines can safely access during eh processing 587 protected by host_lock */
588 * without acquiring the lock.
589 */
590 unsigned int host_busy; /* commands actually active on low-level */
591 unsigned int host_failed; /* commands that failed. */
592 unsigned int host_eh_scheduled; /* EH scheduled without command */ 588 unsigned int host_eh_scheduled; /* EH scheduled without command */
593 589
594 unsigned int host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */ 590 unsigned int host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */