Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <hch@lst.de>
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>

+40 -28
+1 -1
drivers/message/fusion/mptsas.c
··· 3763 3763 printk(MYIOC_s_DEBUG_FMT 3764 3764 "SDEV OUTSTANDING CMDS" 3765 3765 "%d\n", ioc->name, 3766 - sdev->device_busy)); 3766 + atomic_read(&sdev->device_busy))); 3767 3767 } 3768 3768 3769 3769 }
+28 -22
drivers/scsi/scsi_lib.c
··· 302 302 spin_unlock_irqrestore(shost->host_lock, flags); 303 303 } 304 304 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); 308 306 } 309 307 310 308 /* ··· 353 355 354 356 static inline int scsi_device_is_busy(struct scsi_device *sdev) 355 357 { 356 - if (sdev->device_busy >= sdev->queue_depth || sdev->device_blocked) 358 + if (atomic_read(&sdev->device_busy) >= sdev->queue_depth || 359 + sdev->device_blocked) 357 360 return 1; 358 - 359 361 return 0; 360 362 } 361 363 ··· 1202 1204 * queue must be restarted, so we schedule a callback to happen 1203 1205 * shortly. 1204 1206 */ 1205 - if (sdev->device_busy == 0) 1207 + if (atomic_read(&sdev->device_busy) == 0) 1206 1208 blk_delay_queue(q, SCSI_QUEUE_DELAY); 1207 1209 break; 1208 1210 default: ··· 1253 1255 static inline int scsi_dev_queue_ready(struct request_queue *q, 1254 1256 struct scsi_device *sdev) 1255 1257 { 1256 - if (sdev->device_busy == 0 && sdev->device_blocked) { 1258 + unsigned int busy; 1259 + 1260 + busy = atomic_inc_return(&sdev->device_busy) - 1; 1261 + if (sdev->device_blocked) { 1262 + if (busy) 1263 + goto out_dec; 1264 + 1257 1265 /* 1258 1266 * unblock after device_blocked iterates to zero 1259 1267 */ 1260 - if (--sdev->device_blocked == 0) { 1261 - SCSI_LOG_MLQUEUE(3, 1262 - sdev_printk(KERN_INFO, sdev, 1263 - "unblocking device at zero depth\n")); 1264 - } else { 1268 + if (--sdev->device_blocked != 0) { 1265 1269 blk_delay_queue(q, SCSI_QUEUE_DELAY); 1266 - return 0; 1270 + goto out_dec; 1267 1271 } 1272 + SCSI_LOG_MLQUEUE(3, sdev_printk(KERN_INFO, sdev, 1273 + "unblocking device at zero depth\n")); 1268 1274 } 1269 - if (scsi_device_is_busy(sdev)) 1270 - return 0; 1275 + 1276 + if (busy >= sdev->queue_depth) 1277 + goto out_dec; 1271 1278 1272 1279 return 1; 1280 + out_dec: 1281 + atomic_dec(&sdev->device_busy); 1282 + return 0; 1273 1283 } 1274 - 1275 1284 1276 1285 /* 1277 1286 * scsi_target_queue_ready: checks if there we can send commands to target ··· 1453 1448 * bump busy counts. To bump the counters, we need to dance 1454 1449 * with the locks as normal issue path does. 1455 1450 */ 1456 - sdev->device_busy++; 1451 + atomic_inc(&sdev->device_busy); 1457 1452 atomic_inc(&shost->host_busy); 1458 1453 atomic_inc(&starget->target_busy); 1459 1454 ··· 1549 1544 * accept it. 1550 1545 */ 1551 1546 req = blk_peek_request(q); 1552 - if (!req || !scsi_dev_queue_ready(q, sdev)) 1547 + if (!req) 1553 1548 break; 1554 1549 1555 1550 if (unlikely(!scsi_device_online(sdev))) { ··· 1559 1554 continue; 1560 1555 } 1561 1556 1557 + if (!scsi_dev_queue_ready(q, sdev)) 1558 + break; 1562 1559 1563 1560 /* 1564 1561 * Remove the request from the request list. 1565 1562 */ 1566 1563 if (!(blk_queue_tagged(q) && !blk_queue_start_tag(q, req))) 1567 1564 blk_start_request(req); 1568 - sdev->device_busy++; 1569 1565 1570 1566 spin_unlock_irq(q->queue_lock); 1571 1567 cmd = req->special; ··· 1636 1630 */ 1637 1631 spin_lock_irq(q->queue_lock); 1638 1632 blk_requeue_request(q, req); 1639 - sdev->device_busy--; 1633 + atomic_dec(&sdev->device_busy); 1640 1634 out_delay: 1641 - if (sdev->device_busy == 0 && !scsi_device_blocked(sdev)) 1635 + if (atomic_read(&sdev->device_busy) && !scsi_device_blocked(sdev)) 1642 1636 blk_delay_queue(q, SCSI_QUEUE_DELAY); 1643 1637 } 1644 1638 ··· 2377 2371 return err; 2378 2372 2379 2373 scsi_run_queue(sdev->request_queue); 2380 - while (sdev->device_busy) { 2374 + while (atomic_read(&sdev->device_busy)) { 2381 2375 msleep_interruptible(200); 2382 2376 scsi_run_queue(sdev->request_queue); 2383 2377 }
+9 -1
drivers/scsi/scsi_sysfs.c
··· 585 585 * Create the actual show/store functions and data structures. 586 586 */ 587 587 sdev_rd_attr (device_blocked, "%d\n"); 588 - sdev_rd_attr (device_busy, "%d\n"); 589 588 sdev_rd_attr (type, "%d\n"); 590 589 sdev_rd_attr (scsi_level, "%d\n"); 591 590 sdev_rd_attr (vendor, "%.8s\n"); 592 591 sdev_rd_attr (model, "%.16s\n"); 593 592 sdev_rd_attr (rev, "%.4s\n"); 593 + 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); 594 602 595 603 /* 596 604 * TODO: can we make these symlinks to the block layer ones?
+1 -1
drivers/scsi/sg.c
··· 2574 2574 scsidp->id, scsidp->lun, (int) scsidp->type, 2575 2575 1, 2576 2576 (int) scsidp->queue_depth, 2577 - (int) scsidp->device_busy, 2577 + (int) atomic_read(&scsidp->device_busy), 2578 2578 (int) scsi_device_online(scsidp)); 2579 2579 } 2580 2580 read_unlock_irqrestore(&sg_index_lock, iflags);
+1 -3
include/scsi/scsi_device.h
··· 81 81 struct list_head siblings; /* list of all devices on this host */ 82 82 struct list_head same_target_siblings; /* just the devices sharing same target id */ 83 83 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 */ 87 85 spinlock_t list_lock; 88 86 struct list_head cmd_list; /* queue of in use SCSI Command structures */ 89 87 struct list_head starved_entry;