Skip to content

Commit 71e75c9

Browse files
author
Christoph Hellwig
committed
scsi: convert device_busy to atomic_t
Avoid taking the queue_lock to check the per-device 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. Unlike the host and target busy counters this doesn't allow us to avoid the queue_lock in the request_fn due to the way the interface works, but it'll allow us to prepare for using the blk-mq code, which doesn't use the queue_lock at all, and it at least avoids a queue_lock round trip in scsi_device_unbusy, which is still important given how busy the queue_lock is. Signed-off-by: Christoph Hellwig <[email protected]> Reviewed-by: Hannes Reinecke <[email protected]> Reviewed-by: Webb Scales <[email protected]> Acked-by: Jens Axboe <[email protected]> Tested-by: Bart Van Assche <[email protected]> Tested-by: Robert Elliott <[email protected]>
1 parent 7466501 commit 71e75c9

File tree

5 files changed

+40
-28
lines changed

5 files changed

+40
-28
lines changed

drivers/message/fusion/mptsas.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3763,7 +3763,7 @@ mptsas_send_link_status_event(struct fw_event_work *fw_event)
37633763
printk(MYIOC_s_DEBUG_FMT
37643764
"SDEV OUTSTANDING CMDS"
37653765
"%d\n", ioc->name,
3766-
sdev->device_busy));
3766+
atomic_read(&sdev->device_busy)));
37673767
}
37683768

37693769
}

drivers/scsi/scsi_lib.c

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -302,9 +302,7 @@ void scsi_device_unbusy(struct scsi_device *sdev)
302302
spin_unlock_irqrestore(shost->host_lock, flags);
303303
}
304304

305-
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
306-
sdev->device_busy--;
307-
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
305+
atomic_dec(&sdev->device_busy);
308306
}
309307

310308
/*
@@ -355,9 +353,9 @@ static void scsi_single_lun_run(struct scsi_device *current_sdev)
355353

356354
static inline int scsi_device_is_busy(struct scsi_device *sdev)
357355
{
358-
if (sdev->device_busy >= sdev->queue_depth || sdev->device_blocked)
356+
if (atomic_read(&sdev->device_busy) >= sdev->queue_depth ||
357+
sdev->device_blocked)
359358
return 1;
360-
361359
return 0;
362360
}
363361

@@ -1204,7 +1202,7 @@ scsi_prep_return(struct request_queue *q, struct request *req, int ret)
12041202
* queue must be restarted, so we schedule a callback to happen
12051203
* shortly.
12061204
*/
1207-
if (sdev->device_busy == 0)
1205+
if (atomic_read(&sdev->device_busy) == 0)
12081206
blk_delay_queue(q, SCSI_QUEUE_DELAY);
12091207
break;
12101208
default:
@@ -1255,26 +1253,33 @@ static void scsi_unprep_fn(struct request_queue *q, struct request *req)
12551253
static inline int scsi_dev_queue_ready(struct request_queue *q,
12561254
struct scsi_device *sdev)
12571255
{
1258-
if (sdev->device_busy == 0 && sdev->device_blocked) {
1256+
unsigned int busy;
1257+
1258+
busy = atomic_inc_return(&sdev->device_busy) - 1;
1259+
if (sdev->device_blocked) {
1260+
if (busy)
1261+
goto out_dec;
1262+
12591263
/*
12601264
* unblock after device_blocked iterates to zero
12611265
*/
1262-
if (--sdev->device_blocked == 0) {
1263-
SCSI_LOG_MLQUEUE(3,
1264-
sdev_printk(KERN_INFO, sdev,
1265-
"unblocking device at zero depth\n"));
1266-
} else {
1266+
if (--sdev->device_blocked != 0) {
12671267
blk_delay_queue(q, SCSI_QUEUE_DELAY);
1268-
return 0;
1268+
goto out_dec;
12691269
}
1270+
SCSI_LOG_MLQUEUE(3, sdev_printk(KERN_INFO, sdev,
1271+
"unblocking device at zero depth\n"));
12701272
}
1271-
if (scsi_device_is_busy(sdev))
1272-
return 0;
1273+
1274+
if (busy >= sdev->queue_depth)
1275+
goto out_dec;
12731276

12741277
return 1;
1278+
out_dec:
1279+
atomic_dec(&sdev->device_busy);
1280+
return 0;
12751281
}
12761282

1277-
12781283
/*
12791284
* scsi_target_queue_ready: checks if there we can send commands to target
12801285
* @sdev: scsi device on starget to check.
@@ -1448,7 +1453,7 @@ static void scsi_kill_request(struct request *req, struct request_queue *q)
14481453
* bump busy counts. To bump the counters, we need to dance
14491454
* with the locks as normal issue path does.
14501455
*/
1451-
sdev->device_busy++;
1456+
atomic_inc(&sdev->device_busy);
14521457
atomic_inc(&shost->host_busy);
14531458
atomic_inc(&starget->target_busy);
14541459

@@ -1544,7 +1549,7 @@ static void scsi_request_fn(struct request_queue *q)
15441549
* accept it.
15451550
*/
15461551
req = blk_peek_request(q);
1547-
if (!req || !scsi_dev_queue_ready(q, sdev))
1552+
if (!req)
15481553
break;
15491554

15501555
if (unlikely(!scsi_device_online(sdev))) {
@@ -1554,13 +1559,14 @@ static void scsi_request_fn(struct request_queue *q)
15541559
continue;
15551560
}
15561561

1562+
if (!scsi_dev_queue_ready(q, sdev))
1563+
break;
15571564

15581565
/*
15591566
* Remove the request from the request list.
15601567
*/
15611568
if (!(blk_queue_tagged(q) && !blk_queue_start_tag(q, req)))
15621569
blk_start_request(req);
1563-
sdev->device_busy++;
15641570

15651571
spin_unlock_irq(q->queue_lock);
15661572
cmd = req->special;
@@ -1630,9 +1636,9 @@ static void scsi_request_fn(struct request_queue *q)
16301636
*/
16311637
spin_lock_irq(q->queue_lock);
16321638
blk_requeue_request(q, req);
1633-
sdev->device_busy--;
1639+
atomic_dec(&sdev->device_busy);
16341640
out_delay:
1635-
if (sdev->device_busy == 0 && !scsi_device_blocked(sdev))
1641+
if (atomic_read(&sdev->device_busy) && !scsi_device_blocked(sdev))
16361642
blk_delay_queue(q, SCSI_QUEUE_DELAY);
16371643
}
16381644

@@ -2371,7 +2377,7 @@ scsi_device_quiesce(struct scsi_device *sdev)
23712377
return err;
23722378

23732379
scsi_run_queue(sdev->request_queue);
2374-
while (sdev->device_busy) {
2380+
while (atomic_read(&sdev->device_busy)) {
23752381
msleep_interruptible(200);
23762382
scsi_run_queue(sdev->request_queue);
23772383
}

drivers/scsi/scsi_sysfs.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -585,13 +585,21 @@ static int scsi_sdev_check_buf_bit(const char *buf)
585585
* Create the actual show/store functions and data structures.
586586
*/
587587
sdev_rd_attr (device_blocked, "%d\n");
588-
sdev_rd_attr (device_busy, "%d\n");
589588
sdev_rd_attr (type, "%d\n");
590589
sdev_rd_attr (scsi_level, "%d\n");
591590
sdev_rd_attr (vendor, "%.8s\n");
592591
sdev_rd_attr (model, "%.16s\n");
593592
sdev_rd_attr (rev, "%.4s\n");
594593

594+
static ssize_t
595+
sdev_show_device_busy(struct device *dev, struct device_attribute *attr,
596+
char *buf)
597+
{
598+
struct scsi_device *sdev = to_scsi_device(dev);
599+
return snprintf(buf, 20, "%d\n", atomic_read(&sdev->device_busy));
600+
}
601+
static DEVICE_ATTR(device_busy, S_IRUGO, sdev_show_device_busy, NULL);
602+
595603
/*
596604
* TODO: can we make these symlinks to the block layer ones?
597605
*/

drivers/scsi/sg.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2574,7 +2574,7 @@ static int sg_proc_seq_show_dev(struct seq_file *s, void *v)
25742574
scsidp->id, scsidp->lun, (int) scsidp->type,
25752575
1,
25762576
(int) scsidp->queue_depth,
2577-
(int) scsidp->device_busy,
2577+
(int) atomic_read(&scsidp->device_busy),
25782578
(int) scsi_device_online(scsidp));
25792579
}
25802580
read_unlock_irqrestore(&sg_index_lock, iflags);

include/scsi/scsi_device.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,7 @@ struct scsi_device {
8181
struct list_head siblings; /* list of all devices on this host */
8282
struct list_head same_target_siblings; /* just the devices sharing same target id */
8383

84-
/* this is now protected by the request_queue->queue_lock */
85-
unsigned int device_busy; /* commands actually active on
86-
* low-level. protected by queue_lock. */
84+
atomic_t device_busy; /* commands actually active on LLDD */
8785
spinlock_t list_lock;
8886
struct list_head cmd_list; /* queue of in use SCSI Command structures */
8987
struct list_head starved_entry;

0 commit comments

Comments
 (0)