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

[SCSI] iscsi lib: have lib create work queue for transmitting IO

We were using the shost work queue which ended up being
a little akward since all iscsi hosts need a thread for
scanning, but only drivers hooked into libiscsi need
a workqueue for transmitting. So this patch moves the
xmit workqueue to the lib.

Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>

authored by

Mike Christie and committed by
James Bottomley
32ae763e 06d25af4

+48 -16
+1 -1
drivers/infiniband/ulp/iser/iscsi_iser.c
··· 404 404 struct Scsi_Host *shost; 405 405 struct iser_conn *ib_conn; 406 406 407 - shost = iscsi_host_alloc(&iscsi_iser_sht, 0, ISER_DEF_CMD_PER_LUN); 407 + shost = iscsi_host_alloc(&iscsi_iser_sht, 0, ISER_DEF_CMD_PER_LUN, 1); 408 408 if (!shost) 409 409 return NULL; 410 410 shost->transportt = iscsi_iser_scsi_transport;
+1 -1
drivers/infiniband/ulp/iser/iser_initiator.c
··· 661 661 662 662 if (resume_tx) { 663 663 iser_dbg("%ld resuming tx\n",jiffies); 664 - scsi_queue_work(conn->session->host, &conn->xmitwork); 664 + iscsi_conn_queue_work(conn); 665 665 } 666 666 667 667 if (tx_desc->type == ISCSI_TX_CONTROL) {
+1 -1
drivers/scsi/cxgb3i/cxgb3i_iscsi.c
··· 171 171 172 172 shost = iscsi_host_alloc(&cxgb3i_host_template, 173 173 sizeof(struct cxgb3i_hba), 174 - CXGB3I_SCSI_QDEPTH_DFLT); 174 + CXGB3I_SCSI_QDEPTH_DFLT, 1); 175 175 if (!shost) { 176 176 cxgb3i_log_info("iscsi_host_alloc failed.\n"); 177 177 return NULL;
+1 -1
drivers/scsi/cxgb3i/cxgb3i_pdu.c
··· 479 479 cxgb3i_tx_debug("cn 0x%p.\n", c3cn); 480 480 if (conn) { 481 481 cxgb3i_tx_debug("cn 0x%p, cid %d.\n", c3cn, conn->id); 482 - scsi_queue_work(conn->session->host, &conn->xmitwork); 482 + iscsi_conn_queue_work(conn); 483 483 } 484 484 } 485 485
+2 -2
drivers/scsi/iscsi_tcp.c
··· 166 166 167 167 tcp_sw_conn->old_write_space(sk); 168 168 ISCSI_SW_TCP_DBG(conn, "iscsi_write_space\n"); 169 - scsi_queue_work(conn->session->host, &conn->xmitwork); 169 + iscsi_conn_queue_work(conn); 170 170 } 171 171 172 172 static void iscsi_sw_tcp_conn_set_callbacks(struct iscsi_conn *conn) ··· 777 777 return NULL; 778 778 } 779 779 780 - shost = iscsi_host_alloc(&iscsi_sw_tcp_sht, 0, qdepth); 780 + shost = iscsi_host_alloc(&iscsi_sw_tcp_sht, 0, qdepth, 1); 781 781 if (!shost) 782 782 return NULL; 783 783 shost->transportt = iscsi_sw_tcp_scsi_transport;
+36 -9
drivers/scsi/libiscsi.c
··· 76 76 (n1 > n2 && (n2 - n1 < SNA32_CHECK))); 77 77 } 78 78 79 + inline void iscsi_conn_queue_work(struct iscsi_conn *conn) 80 + { 81 + struct Scsi_Host *shost = conn->session->host; 82 + struct iscsi_host *ihost = shost_priv(shost); 83 + 84 + queue_work(ihost->workq, &conn->xmitwork); 85 + } 86 + EXPORT_SYMBOL_GPL(iscsi_conn_queue_work); 87 + 79 88 void 80 89 iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) 81 90 { ··· 112 103 if (!list_empty(&session->leadconn->xmitqueue) || 113 104 !list_empty(&session->leadconn->mgmtqueue)) { 114 105 if (!(session->tt->caps & CAP_DATA_PATH_OFFLOAD)) 115 - scsi_queue_work(session->host, 116 - &session->leadconn->xmitwork); 106 + iscsi_conn_queue_work(session->leadconn); 117 107 } 118 108 } 119 109 } ··· 594 586 goto free_task; 595 587 596 588 } else 597 - scsi_queue_work(conn->session->host, &conn->xmitwork); 589 + iscsi_conn_queue_work(conn); 598 590 599 591 return task; 600 592 ··· 1168 1160 struct iscsi_conn *conn = task->conn; 1169 1161 1170 1162 list_move_tail(&task->running, &conn->requeue); 1171 - scsi_queue_work(conn->session->host, &conn->xmitwork); 1163 + iscsi_conn_queue_work(conn); 1172 1164 } 1173 1165 EXPORT_SYMBOL_GPL(iscsi_requeue_task); 1174 1166 ··· 1421 1413 goto prepd_reject; 1422 1414 } 1423 1415 } else 1424 - scsi_queue_work(session->host, &conn->xmitwork); 1416 + iscsi_conn_queue_work(conn); 1425 1417 1426 1418 session->queued_cmdsn++; 1427 1419 spin_unlock(&session->lock); ··· 1639 1631 1640 1632 void iscsi_suspend_tx(struct iscsi_conn *conn) 1641 1633 { 1634 + struct Scsi_Host *shost = conn->session->host; 1635 + struct iscsi_host *ihost = shost_priv(shost); 1636 + 1642 1637 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); 1643 1638 if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD)) 1644 - scsi_flush_work(conn->session->host); 1639 + flush_workqueue(ihost->workq); 1645 1640 } 1646 1641 EXPORT_SYMBOL_GPL(iscsi_suspend_tx); 1647 1642 ··· 1652 1641 { 1653 1642 clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); 1654 1643 if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD)) 1655 - scsi_queue_work(conn->session->host, &conn->xmitwork); 1644 + iscsi_conn_queue_work(conn); 1656 1645 } 1657 1646 1658 1647 static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd) ··· 2057 2046 * @sht: scsi host template 2058 2047 * @dd_data_size: driver host data size 2059 2048 * @qdepth: default device queue depth 2049 + * @xmit_can_sleep: bool indicating if LLD will queue IO from a work queue 2060 2050 * 2061 2051 * This should be called by partial offload and software iscsi drivers. 2062 2052 * To access the driver specific memory use the iscsi_host_priv() macro. 2063 2053 */ 2064 2054 struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht, 2065 - int dd_data_size, uint16_t qdepth) 2055 + int dd_data_size, uint16_t qdepth, 2056 + bool xmit_can_sleep) 2066 2057 { 2067 2058 struct Scsi_Host *shost; 2068 2059 struct iscsi_host *ihost; ··· 2076 2063 if (qdepth == 0) 2077 2064 qdepth = ISCSI_DEF_CMD_PER_LUN; 2078 2065 shost->cmd_per_lun = qdepth; 2079 - 2080 2066 ihost = shost_priv(shost); 2067 + 2068 + if (xmit_can_sleep) { 2069 + snprintf(ihost->workq_name, sizeof(ihost->workq_name), 2070 + "iscsi_q_%d", shost->host_no); 2071 + ihost->workq = create_singlethread_workqueue(ihost->workq_name); 2072 + if (!ihost->workq) 2073 + goto free_host; 2074 + } 2075 + 2081 2076 spin_lock_init(&ihost->lock); 2082 2077 ihost->state = ISCSI_HOST_SETUP; 2083 2078 ihost->num_sessions = 0; 2084 2079 init_waitqueue_head(&ihost->session_removal_wq); 2085 2080 return shost; 2081 + 2082 + free_host: 2083 + scsi_host_put(shost); 2084 + return NULL; 2086 2085 } 2087 2086 EXPORT_SYMBOL_GPL(iscsi_host_alloc); 2088 2087 ··· 2126 2101 flush_signals(current); 2127 2102 2128 2103 scsi_remove_host(shost); 2104 + if (ihost->workq) 2105 + destroy_workqueue(ihost->workq); 2129 2106 } 2130 2107 EXPORT_SYMBOL_GPL(iscsi_host_remove); 2131 2108
+6 -1
include/scsi/libiscsi.h
··· 318 318 spinlock_t lock; 319 319 int num_sessions; 320 320 int state; 321 + 322 + struct workqueue_struct *workq; 323 + char workq_name[20]; 321 324 }; 322 325 323 326 /* ··· 346 343 enum iscsi_host_param param, char *buf); 347 344 extern int iscsi_host_add(struct Scsi_Host *shost, struct device *pdev); 348 345 extern struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht, 349 - int dd_data_size, uint16_t qdepth); 346 + int dd_data_size, uint16_t qdepth, 347 + bool xmit_can_sleep); 350 348 extern void iscsi_host_remove(struct Scsi_Host *shost); 351 349 extern void iscsi_host_free(struct Scsi_Host *shost); 352 350 ··· 383 379 extern int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, 384 380 enum iscsi_param param, char *buf); 385 381 extern void iscsi_suspend_tx(struct iscsi_conn *conn); 382 + extern void iscsi_conn_queue_work(struct iscsi_conn *conn); 386 383 387 384 #define iscsi_conn_printk(prefix, _c, fmt, a...) \ 388 385 iscsi_cls_conn_printk(prefix, ((struct iscsi_conn *)_c)->cls_conn, \