Skip to content

Commit df480d9

Browse files
sumitsaxena11kawasaki
authored andcommitted
scsi: use percpu counters for iorequest_cnt and iodone_cnt
iorequest_cnt and iodone_cnt are updated on every command dispatch and completion, often from different CPUs on high queue depth workloads. Using adjacent atomic_t fields caused cache line contention between the submission and completion paths. Represent these statistics with struct percpu_counter so increments are mostly local to each CPU, avoiding false sharing without growing struct scsi_device further for cache-line padding. Suggested-by: Bart Van Assche <[email protected]> Signed-off-by: Sumit Saxena <[email protected]>
1 parent 2cc3f24 commit df480d9

5 files changed

Lines changed: 40 additions & 11 deletions

File tree

drivers/scsi/scsi_error.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ enum blk_eh_timer_return scsi_timeout(struct request *req)
370370
*/
371371
if (test_and_set_bit(SCMD_STATE_COMPLETE, &scmd->state))
372372
return BLK_EH_DONE;
373-
atomic_inc(&scmd->device->iodone_cnt);
373+
percpu_counter_inc(&scmd->device->iodone_cnt);
374374
if (scsi_abort_command(scmd) != SUCCESS) {
375375
set_host_byte(scmd, DID_TIME_OUT);
376376
scsi_eh_scmd_add(scmd);

drivers/scsi/scsi_lib.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1554,7 +1554,7 @@ static void scsi_complete(struct request *rq)
15541554

15551555
INIT_LIST_HEAD(&cmd->eh_entry);
15561556

1557-
atomic_inc(&cmd->device->iodone_cnt);
1557+
percpu_counter_inc(&cmd->device->iodone_cnt);
15581558
if (cmd->result)
15591559
atomic_inc(&cmd->device->ioerr_cnt);
15601560

@@ -1592,7 +1592,7 @@ static enum scsi_qc_status scsi_dispatch_cmd(struct scsi_cmnd *cmd)
15921592
struct Scsi_Host *host = cmd->device->host;
15931593
int rtn = 0;
15941594

1595-
atomic_inc(&cmd->device->iorequest_cnt);
1595+
percpu_counter_inc(&cmd->device->iorequest_cnt);
15961596

15971597
/* check if the device is still usable */
15981598
if (unlikely(cmd->device->sdev_state == SDEV_DEL)) {
@@ -1614,7 +1614,7 @@ static enum scsi_qc_status scsi_dispatch_cmd(struct scsi_cmnd *cmd)
16141614
*/
16151615
SCSI_LOG_MLQUEUE(3, scmd_printk(KERN_INFO, cmd,
16161616
"queuecommand : device blocked\n"));
1617-
atomic_dec(&cmd->device->iorequest_cnt);
1617+
percpu_counter_dec(&cmd->device->iorequest_cnt);
16181618
return SCSI_MLQUEUE_DEVICE_BUSY;
16191619
}
16201620

@@ -1647,7 +1647,7 @@ static enum scsi_qc_status scsi_dispatch_cmd(struct scsi_cmnd *cmd)
16471647
trace_scsi_dispatch_cmd_start(cmd);
16481648
rtn = host->hostt->queuecommand(host, cmd);
16491649
if (rtn) {
1650-
atomic_dec(&cmd->device->iorequest_cnt);
1650+
percpu_counter_dec(&cmd->device->iorequest_cnt);
16511651
trace_scsi_dispatch_cmd_error(cmd, rtn);
16521652
if (rtn != SCSI_MLQUEUE_DEVICE_BUSY &&
16531653
rtn != SCSI_MLQUEUE_TARGET_BUSY)

drivers/scsi/scsi_scan.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,15 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
351351

352352
scsi_sysfs_device_initialize(sdev);
353353

354+
ret = percpu_counter_init(&sdev->iorequest_cnt, 0, GFP_KERNEL);
355+
if (ret)
356+
goto out_device_destroy;
357+
ret = percpu_counter_init(&sdev->iodone_cnt, 0, GFP_KERNEL);
358+
if (ret) {
359+
percpu_counter_destroy(&sdev->iorequest_cnt);
360+
goto out_device_destroy;
361+
}
362+
354363
if (scsi_device_is_pseudo_dev(sdev))
355364
return sdev;
356365

drivers/scsi/scsi_sysfs.c

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,10 @@ static void scsi_device_dev_release(struct device *dev)
516516
if (vpd_pgb7)
517517
kfree_rcu(vpd_pgb7, rcu);
518518
kfree(sdev->inquiry);
519+
if (percpu_counter_initialized(&sdev->iodone_cnt))
520+
percpu_counter_destroy(&sdev->iodone_cnt);
521+
if (percpu_counter_initialized(&sdev->iorequest_cnt))
522+
percpu_counter_destroy(&sdev->iorequest_cnt);
519523
kfree(sdev);
520524

521525
if (parent)
@@ -936,11 +940,26 @@ static ssize_t
936940
show_iostat_counterbits(struct device *dev, struct device_attribute *attr,
937941
char *buf)
938942
{
939-
return snprintf(buf, 20, "%d\n", (int)sizeof(atomic_t) * 8);
943+
/*
944+
* iorequest_cnt and iodone_cnt are per-CPU sums (s64); ioerr_cnt and
945+
* iotmo_cnt remain atomic_t. Report the widest counter for tools.
946+
*/
947+
return snprintf(buf, 20, "%zu\n", sizeof(s64) * 8);
940948
}
941949

942950
static DEVICE_ATTR(iocounterbits, S_IRUGO, show_iostat_counterbits, NULL);
943951

952+
#define show_sdev_iostat_percpu(field) \
953+
static ssize_t \
954+
show_iostat_##field(struct device *dev, struct device_attribute *attr, \
955+
char *buf) \
956+
{ \
957+
struct scsi_device *sdev = to_scsi_device(dev); \
958+
unsigned long long count = percpu_counter_sum(&sdev->field); \
959+
return snprintf(buf, 20, "0x%llx\n", count); \
960+
} \
961+
static DEVICE_ATTR(field, 0444, show_iostat_##field, NULL)
962+
944963
#define show_sdev_iostat(field) \
945964
static ssize_t \
946965
show_iostat_##field(struct device *dev, struct device_attribute *attr, \
@@ -950,10 +969,10 @@ show_iostat_##field(struct device *dev, struct device_attribute *attr, \
950969
unsigned long long count = atomic_read(&sdev->field); \
951970
return snprintf(buf, 20, "0x%llx\n", count); \
952971
} \
953-
static DEVICE_ATTR(field, S_IRUGO, show_iostat_##field, NULL)
972+
static DEVICE_ATTR(field, 0444, show_iostat_##field, NULL)
954973

955-
show_sdev_iostat(iorequest_cnt);
956-
show_sdev_iostat(iodone_cnt);
974+
show_sdev_iostat_percpu(iorequest_cnt);
975+
show_sdev_iostat_percpu(iodone_cnt);
957976
show_sdev_iostat(ioerr_cnt);
958977
show_sdev_iostat(iotmo_cnt);
959978

include/scsi/scsi_device.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <linux/blk-mq.h>
99
#include <scsi/scsi.h>
1010
#include <linux/atomic.h>
11+
#include <linux/percpu_counter.h>
1112
#include <linux/sbitmap.h>
1213

1314
struct bsg_device;
@@ -271,8 +272,8 @@ struct scsi_device {
271272
unsigned int max_device_blocked; /* what device_blocked counts down from */
272273
#define SCSI_DEFAULT_DEVICE_BLOCKED 3
273274

274-
atomic_t iorequest_cnt;
275-
atomic_t iodone_cnt;
275+
struct percpu_counter iorequest_cnt;
276+
struct percpu_counter iodone_cnt;
276277
atomic_t ioerr_cnt;
277278
atomic_t iotmo_cnt;
278279

0 commit comments

Comments
 (0)