Linux过河拆桥策略,Linux那些事儿之我是Block层(8)scsi命令的前世今生(二)

1411 /*

1412  * Function:    scsi_request_fn()

1413  *

1414  * Purpose:     Main strategy routine for SCSI.

1415  *

1416  * Arguments:   q       - Pointer to actual queue.

1417  *

1418  * Returns:     Nothing

1419  *

1420  * Lock status: IO request lock assumed to be held when called.

1421  */

1422 static void scsi_request_fn(struct request_queue *q)

1423 {

1424         struct scsi_device *sdev = q->queuedata;

1425         struct Scsi_Host *shost;

1426         struct scsi_cmnd *cmd;

1427         struct request *req;

1428

1429         if (!sdev) {

1430                 printk("scsi: killing requests for dead queue/n");

1431                 while ((req = elv_next_request(q)) != NULL)

1432                         scsi_kill_request(req, q);

1433                 return;

1434         }

1435

1436         if(!get_device(&sdev->sdev_gendev))

1437                 /* We must be tearing the block queue down already */

1438                 return;

1439

1440         /*

1441          * To start with, we keep looping until the queue is empty, or until

1442          * the host is no longer able to accept any more requests.

1443          */

1444         shost = sdev->host;

1445         while (!blk_queue_plugged(q)) {

1446                 int rtn;

1447                 /*

1448                  * get next queueable request.  We do this early to make sure

1449                  * that the request is fully prepared even if we cannot

1450                  * accept it.

1451                  */

1452                 req = elv_next_request(q);

1453                 if (!req || !scsi_dev_queue_ready(q, sdev))

1454                         break;

1455

1456                 if (unlikely(!scsi_device_online(sdev))) {

1457                         sdev_printk(KERN_ERR, sdev,

1458                                     "rejecting I/O to offline device/n");

1459                         scsi_kill_request(req, q);

1460                         continue;

1461                 }

1462

1463

1464                 /*

1465                  * Remove the request from the request list.

1466                  */

1467                 if (!(blk_queue_tagged(q) && !blk_queue_start_tag(q, req)))

1468                         blkdev_dequeue_request(req);

1469                 sdev->device_busy++;

1470

1471                 spin_unlock(q->queue_lock);

1472                 cmd = req->special;

1473                 if (unlikely(cmd == NULL)) {

1474                         printk(KERN_CRIT "impossible request in %s./n"

1475                                          "please mail a stack trace to "

1476                                          "linux-scsi@vger.kernel.org/n",

1477                                          __FUNCTION__);

1478                         blk_dump_rq_flags(req, "foo");

1479                         BUG();

1480                 }

1481                 spin_lock(shost->host_lock);

1482

1483                 if (!scsi_host_queue_ready(q, shost, sdev))

1484                         goto not_ready;

1485                 if (sdev->single_lun) {

1486                         if (scsi_target(sdev)->starget_sdev_user &&

1487                             scsi_target(sdev)->starget_sdev_user != sdev)

1488                                 goto not_ready;

1489                         scsi_target(sdev)->starget_sdev_user = sdev;

1490                 }

1491                 shost->host_busy++;

1492

1493                 /*

1494                  * XXX(hch): This is rather suboptimal, scsi_dispatch_cmd will

1495                  *              take the lock again.

1496                  */

1497                 spin_unlock_irq(shost->host_lock);

1498

1499                 /*

1500                  * Finally, initialize any error handling parameters, and set up

1501                  * the timers for timeouts.

1502                  */

1503                 scsi_init_cmd_errh(cmd);

1504

1505                 /*

1506                  * Dispatch the command to the low-level driver.

1507                  */

1508                 rtn = scsi_dispatch_cmd(cmd);

1509                 spin_lock_irq(q->queue_lock);

1510                 if(rtn) {

1511                         /* we're refusing the command; because of

1512                          * the way locks get dropped, we need to

1513                          * check here if plugging is required */

1514                         if(sdev->device_busy == 0)

1515                                 blk_plug_device(q);

1516

1517                         break;

1518                 }

1519         }

1520

1521         goto out;

1522

1523  not_ready:

1524         spin_unlock_irq(shost->host_lock);

1525

1526         /*

1527          * lock q, handle tag, requeue req, and decrement device_busy. We

1528          * must return with queue_lock held.

1529          *

1530          * Decrementing device_busy without checking it is OK, as all such

1531          * cases (host limits or settings) should run the queue at some

1532          * later time.

1533          */

1534         spin_lock_irq(q->queue_lock);

1535         blk_requeue_request(q, req);

1536         sdev->device_busy--;

1537         if(sdev->device_busy == 0)

1538                 blk_plug_device(q);

1539  out:

1540         /* must be careful here...if we trigger the ->remove() function

1541          * we cannot be holding the q lock */

1542         spin_unlock_irq(q->queue_lock);

1543         put_device(&sdev->sdev_gendev);

1544         spin_lock_irq(q->queue_lock);

1545 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值