summaryrefslogtreecommitdiffstats
path: root/include/scsi
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2014-01-23 06:07:41 -0500
committerChristoph Hellwig <hch@lst.de>2014-07-25 17:15:48 -0400
commitcd9070c9c512ff7995f9019392e0ae548df3a088 (patch)
treea426fccd5633f429f37dac237d8cf417ad9e7f31 /include/scsi
parent71e75c97f97a9645d25fbf3d8e4165a558f18747 (diff)
scsi: fix the {host,target,device}_blocked counter mess
Seems like these counters are missing any sort of synchronization for updates, as a over 10 year old comment from me noted. Fix this by using atomic counters, and while we're at it also make sure they are in the same cacheline as the _busy counters and not needlessly stored to in every I/O completion. With the new model the _busy counters can temporarily go negative, so all the readers are updated to check for > 0 values. Longer term every successful I/O completion will reset the counters to zero, so the temporarily negative values will not cause any harm. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com> 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>
Diffstat (limited to 'include/scsi')
-rw-r--r--include/scsi/scsi_device.h7
-rw-r--r--include/scsi/scsi_host.h7
2 files changed, 6 insertions, 8 deletions
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 3329901c7243..0f853f2c9dc7 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -82,6 +82,8 @@ struct scsi_device {
82 struct list_head same_target_siblings; /* just the devices sharing same target id */ 82 struct list_head same_target_siblings; /* just the devices sharing same target id */
83 83
84 atomic_t device_busy; /* commands actually active on LLDD */ 84 atomic_t device_busy; /* commands actually active on LLDD */
85 atomic_t device_blocked; /* Device returned QUEUE_FULL. */
86
85 spinlock_t list_lock; 87 spinlock_t list_lock;
86 struct list_head cmd_list; /* queue of in use SCSI Command structures */ 88 struct list_head cmd_list; /* queue of in use SCSI Command structures */
87 struct list_head starved_entry; 89 struct list_head starved_entry;
@@ -180,8 +182,6 @@ struct scsi_device {
180 struct list_head event_list; /* asserted events */ 182 struct list_head event_list; /* asserted events */
181 struct work_struct event_work; 183 struct work_struct event_work;
182 184
183 unsigned int device_blocked; /* Device returned QUEUE_FULL. */
184
185 unsigned int max_device_blocked; /* what device_blocked counts down from */ 185 unsigned int max_device_blocked; /* what device_blocked counts down from */
186#define SCSI_DEFAULT_DEVICE_BLOCKED 3 186#define SCSI_DEFAULT_DEVICE_BLOCKED 3
187 187
@@ -291,12 +291,13 @@ struct scsi_target {
291 * the same target will also. */ 291 * the same target will also. */
292 /* commands actually active on LLD. */ 292 /* commands actually active on LLD. */
293 atomic_t target_busy; 293 atomic_t target_busy;
294 atomic_t target_blocked;
295
294 /* 296 /*
295 * LLDs should set this in the slave_alloc host template callout. 297 * LLDs should set this in the slave_alloc host template callout.
296 * If set to zero then there is not limit. 298 * If set to zero then there is not limit.
297 */ 299 */
298 unsigned int can_queue; 300 unsigned int can_queue;
299 unsigned int target_blocked;
300 unsigned int max_target_blocked; 301 unsigned int max_target_blocked;
301#define SCSI_DEFAULT_TARGET_BLOCKED 3 302#define SCSI_DEFAULT_TARGET_BLOCKED 3
302 303
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 51f7911b1cbb..5e8ebc1ac12b 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -583,6 +583,8 @@ struct Scsi_Host {
583 struct blk_queue_tag *bqt; 583 struct blk_queue_tag *bqt;
584 584
585 atomic_t host_busy; /* commands actually active on low-level */ 585 atomic_t host_busy; /* commands actually active on low-level */
586 atomic_t host_blocked;
587
586 unsigned int host_failed; /* commands that failed. 588 unsigned int host_failed; /* commands that failed.
587 protected by host_lock */ 589 protected by host_lock */
588 unsigned int host_eh_scheduled; /* EH scheduled without command */ 590 unsigned int host_eh_scheduled; /* EH scheduled without command */
@@ -682,11 +684,6 @@ struct Scsi_Host {
682 struct workqueue_struct *tmf_work_q; 684 struct workqueue_struct *tmf_work_q;
683 685
684 /* 686 /*
685 * Host has rejected a command because it was busy.
686 */
687 unsigned int host_blocked;
688
689 /*
690 * Value host_blocked counts down from 687 * Value host_blocked counts down from
691 */ 688 */
692 unsigned int max_host_blocked; 689 unsigned int max_host_blocked;