aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorChris Leech <cleech@redhat.com>2017-02-27 19:58:36 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-03-26 07:05:58 -0400
commitde1ff848c74fcc5b172323c1d5fac88dc1ab0281 (patch)
treeda66d445034267e0ca8f5937264bd4cf7b7016d2 /drivers/scsi
parent42ba2c265b085a83a3b18ddb6e087f231c97e02e (diff)
scsi: libiscsi: add lock around task lists to fix list corruption regression
commit 6f8830f5bbab16e54f261de187f3df4644a5b977 upstream. There's a rather long standing regression from the commit "libiscsi: Reduce locking contention in fast path" Depending on iSCSI target behavior, it's possible to hit the case in iscsi_complete_task where the task is still on a pending list (!list_empty(&task->running)). When that happens the task is removed from the list while holding the session back_lock, but other task list modification occur under the frwd_lock. That leads to linked list corruption and eventually a panicked system. Rather than back out the session lock split entirely, in order to try and keep some of the performance gains this patch adds another lock to maintain the task lists integrity. Major enterprise supported kernels have been backing out the lock split for while now, thanks to the efforts at IBM where a lab setup has the most reliable reproducer I've seen on this issue. This patch has been tested there successfully. Signed-off-by: Chris Leech <cleech@redhat.com> Fixes: 659743b02c41 ("[SCSI] libiscsi: Reduce locking contention in fast path") Reported-by: Prashantha Subbarao <psubbara@us.ibm.com> Reviewed-by: Guilherme G. Piccoli <gpiccoli@linux.vnet.ibm.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/libiscsi.c26
1 files changed, 25 insertions, 1 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index f9b6fba689ff..a530f08592cd 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -560,8 +560,12 @@ static void iscsi_complete_task(struct iscsi_task *task, int state)
560 WARN_ON_ONCE(task->state == ISCSI_TASK_FREE); 560 WARN_ON_ONCE(task->state == ISCSI_TASK_FREE);
561 task->state = state; 561 task->state = state;
562 562
563 if (!list_empty(&task->running)) 563 spin_lock_bh(&conn->taskqueuelock);
564 if (!list_empty(&task->running)) {
565 pr_debug_once("%s while task on list", __func__);
564 list_del_init(&task->running); 566 list_del_init(&task->running);
567 }
568 spin_unlock_bh(&conn->taskqueuelock);
565 569
566 if (conn->task == task) 570 if (conn->task == task)
567 conn->task = NULL; 571 conn->task = NULL;
@@ -783,7 +787,9 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
783 if (session->tt->xmit_task(task)) 787 if (session->tt->xmit_task(task))
784 goto free_task; 788 goto free_task;
785 } else { 789 } else {
790 spin_lock_bh(&conn->taskqueuelock);
786 list_add_tail(&task->running, &conn->mgmtqueue); 791 list_add_tail(&task->running, &conn->mgmtqueue);
792 spin_unlock_bh(&conn->taskqueuelock);
787 iscsi_conn_queue_work(conn); 793 iscsi_conn_queue_work(conn);
788 } 794 }
789 795
@@ -1474,8 +1480,10 @@ void iscsi_requeue_task(struct iscsi_task *task)
1474 * this may be on the requeue list already if the xmit_task callout 1480 * this may be on the requeue list already if the xmit_task callout
1475 * is handling the r2ts while we are adding new ones 1481 * is handling the r2ts while we are adding new ones
1476 */ 1482 */
1483 spin_lock_bh(&conn->taskqueuelock);
1477 if (list_empty(&task->running)) 1484 if (list_empty(&task->running))
1478 list_add_tail(&task->running, &conn->requeue); 1485 list_add_tail(&task->running, &conn->requeue);
1486 spin_unlock_bh(&conn->taskqueuelock);
1479 iscsi_conn_queue_work(conn); 1487 iscsi_conn_queue_work(conn);
1480} 1488}
1481EXPORT_SYMBOL_GPL(iscsi_requeue_task); 1489EXPORT_SYMBOL_GPL(iscsi_requeue_task);
@@ -1512,22 +1520,26 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
1512 * only have one nop-out as a ping from us and targets should not 1520 * only have one nop-out as a ping from us and targets should not
1513 * overflow us with nop-ins 1521 * overflow us with nop-ins
1514 */ 1522 */
1523 spin_lock_bh(&conn->taskqueuelock);
1515check_mgmt: 1524check_mgmt:
1516 while (!list_empty(&conn->mgmtqueue)) { 1525 while (!list_empty(&conn->mgmtqueue)) {
1517 conn->task = list_entry(conn->mgmtqueue.next, 1526 conn->task = list_entry(conn->mgmtqueue.next,
1518 struct iscsi_task, running); 1527 struct iscsi_task, running);
1519 list_del_init(&conn->task->running); 1528 list_del_init(&conn->task->running);
1529 spin_unlock_bh(&conn->taskqueuelock);
1520 if (iscsi_prep_mgmt_task(conn, conn->task)) { 1530 if (iscsi_prep_mgmt_task(conn, conn->task)) {
1521 /* regular RX path uses back_lock */ 1531 /* regular RX path uses back_lock */
1522 spin_lock_bh(&conn->session->back_lock); 1532 spin_lock_bh(&conn->session->back_lock);
1523 __iscsi_put_task(conn->task); 1533 __iscsi_put_task(conn->task);
1524 spin_unlock_bh(&conn->session->back_lock); 1534 spin_unlock_bh(&conn->session->back_lock);
1525 conn->task = NULL; 1535 conn->task = NULL;
1536 spin_lock_bh(&conn->taskqueuelock);
1526 continue; 1537 continue;
1527 } 1538 }
1528 rc = iscsi_xmit_task(conn); 1539 rc = iscsi_xmit_task(conn);
1529 if (rc) 1540 if (rc)
1530 goto done; 1541 goto done;
1542 spin_lock_bh(&conn->taskqueuelock);
1531 } 1543 }
1532 1544
1533 /* process pending command queue */ 1545 /* process pending command queue */
@@ -1535,19 +1547,24 @@ check_mgmt:
1535 conn->task = list_entry(conn->cmdqueue.next, struct iscsi_task, 1547 conn->task = list_entry(conn->cmdqueue.next, struct iscsi_task,
1536 running); 1548 running);
1537 list_del_init(&conn->task->running); 1549 list_del_init(&conn->task->running);
1550 spin_unlock_bh(&conn->taskqueuelock);
1538 if (conn->session->state == ISCSI_STATE_LOGGING_OUT) { 1551 if (conn->session->state == ISCSI_STATE_LOGGING_OUT) {
1539 fail_scsi_task(conn->task, DID_IMM_RETRY); 1552 fail_scsi_task(conn->task, DID_IMM_RETRY);
1553 spin_lock_bh(&conn->taskqueuelock);
1540 continue; 1554 continue;
1541 } 1555 }
1542 rc = iscsi_prep_scsi_cmd_pdu(conn->task); 1556 rc = iscsi_prep_scsi_cmd_pdu(conn->task);
1543 if (rc) { 1557 if (rc) {
1544 if (rc == -ENOMEM || rc == -EACCES) { 1558 if (rc == -ENOMEM || rc == -EACCES) {
1559 spin_lock_bh(&conn->taskqueuelock);
1545 list_add_tail(&conn->task->running, 1560 list_add_tail(&conn->task->running,
1546 &conn->cmdqueue); 1561 &conn->cmdqueue);
1547 conn->task = NULL; 1562 conn->task = NULL;
1563 spin_unlock_bh(&conn->taskqueuelock);
1548 goto done; 1564 goto done;
1549 } else 1565 } else
1550 fail_scsi_task(conn->task, DID_ABORT); 1566 fail_scsi_task(conn->task, DID_ABORT);
1567 spin_lock_bh(&conn->taskqueuelock);
1551 continue; 1568 continue;
1552 } 1569 }
1553 rc = iscsi_xmit_task(conn); 1570 rc = iscsi_xmit_task(conn);
@@ -1558,6 +1575,7 @@ check_mgmt:
1558 * we need to check the mgmt queue for nops that need to 1575 * we need to check the mgmt queue for nops that need to
1559 * be sent to aviod starvation 1576 * be sent to aviod starvation
1560 */ 1577 */
1578 spin_lock_bh(&conn->taskqueuelock);
1561 if (!list_empty(&conn->mgmtqueue)) 1579 if (!list_empty(&conn->mgmtqueue))
1562 goto check_mgmt; 1580 goto check_mgmt;
1563 } 1581 }
@@ -1577,12 +1595,15 @@ check_mgmt:
1577 conn->task = task; 1595 conn->task = task;
1578 list_del_init(&conn->task->running); 1596 list_del_init(&conn->task->running);
1579 conn->task->state = ISCSI_TASK_RUNNING; 1597 conn->task->state = ISCSI_TASK_RUNNING;
1598 spin_unlock_bh(&conn->taskqueuelock);
1580 rc = iscsi_xmit_task(conn); 1599 rc = iscsi_xmit_task(conn);
1581 if (rc) 1600 if (rc)
1582 goto done; 1601 goto done;
1602 spin_lock_bh(&conn->taskqueuelock);
1583 if (!list_empty(&conn->mgmtqueue)) 1603 if (!list_empty(&conn->mgmtqueue))
1584 goto check_mgmt; 1604 goto check_mgmt;
1585 } 1605 }
1606 spin_unlock_bh(&conn->taskqueuelock);
1586 spin_unlock_bh(&conn->session->frwd_lock); 1607 spin_unlock_bh(&conn->session->frwd_lock);
1587 return -ENODATA; 1608 return -ENODATA;
1588 1609
@@ -1738,7 +1759,9 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
1738 goto prepd_reject; 1759 goto prepd_reject;
1739 } 1760 }
1740 } else { 1761 } else {
1762 spin_lock_bh(&conn->taskqueuelock);
1741 list_add_tail(&task->running, &conn->cmdqueue); 1763 list_add_tail(&task->running, &conn->cmdqueue);
1764 spin_unlock_bh(&conn->taskqueuelock);
1742 iscsi_conn_queue_work(conn); 1765 iscsi_conn_queue_work(conn);
1743 } 1766 }
1744 1767
@@ -2897,6 +2920,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
2897 INIT_LIST_HEAD(&conn->mgmtqueue); 2920 INIT_LIST_HEAD(&conn->mgmtqueue);
2898 INIT_LIST_HEAD(&conn->cmdqueue); 2921 INIT_LIST_HEAD(&conn->cmdqueue);
2899 INIT_LIST_HEAD(&conn->requeue); 2922 INIT_LIST_HEAD(&conn->requeue);
2923 spin_lock_init(&conn->taskqueuelock);
2900 INIT_WORK(&conn->xmitwork, iscsi_xmitworker); 2924 INIT_WORK(&conn->xmitwork, iscsi_xmitworker);
2901 2925
2902 /* allocate login_task used for the login/text sequences */ 2926 /* allocate login_task used for the login/text sequences */