[SCSI] libcxgbi: pdu read fixes
Fixed the locking and releasing skb in the case of error in the pdu read path, and added define iscsi_task_cxgbi_data to access the private data inside the iscsi_task. Signed-off-by: Karen Xie <kxie@chelsio.com> Reviewed-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
This commit is contained in:

committed by
James Bottomley

parent
24d3f95a5b
commit
e3d2ad8cb2
@@ -593,11 +593,11 @@ static void cxgbi_inform_iscsi_conn_closing(struct cxgbi_sock *csk)
|
|||||||
csk, csk->state, csk->flags, csk->user_data);
|
csk, csk->state, csk->flags, csk->user_data);
|
||||||
|
|
||||||
if (csk->state != CTP_ESTABLISHED) {
|
if (csk->state != CTP_ESTABLISHED) {
|
||||||
read_lock(&csk->callback_lock);
|
read_lock_bh(&csk->callback_lock);
|
||||||
if (csk->user_data)
|
if (csk->user_data)
|
||||||
iscsi_conn_failure(csk->user_data,
|
iscsi_conn_failure(csk->user_data,
|
||||||
ISCSI_ERR_CONN_FAILED);
|
ISCSI_ERR_CONN_FAILED);
|
||||||
read_unlock(&csk->callback_lock);
|
read_unlock_bh(&csk->callback_lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1712,12 +1712,10 @@ void cxgbi_conn_pdu_ready(struct cxgbi_sock *csk)
|
|||||||
"csk 0x%p, conn 0x%p, id %d, suspend_rx %lu!\n",
|
"csk 0x%p, conn 0x%p, id %d, suspend_rx %lu!\n",
|
||||||
csk, conn, conn ? conn->id : 0xFF,
|
csk, conn, conn ? conn->id : 0xFF,
|
||||||
conn ? conn->suspend_rx : 0xFF);
|
conn ? conn->suspend_rx : 0xFF);
|
||||||
read_unlock(&csk->callback_lock);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!err) {
|
while (!err) {
|
||||||
read_lock(&csk->callback_lock);
|
|
||||||
skb = skb_peek(&csk->receive_queue);
|
skb = skb_peek(&csk->receive_queue);
|
||||||
if (!skb ||
|
if (!skb ||
|
||||||
!(cxgbi_skcb_test_flag(skb, SKCBF_RX_STATUS))) {
|
!(cxgbi_skcb_test_flag(skb, SKCBF_RX_STATUS))) {
|
||||||
@@ -1725,11 +1723,9 @@ void cxgbi_conn_pdu_ready(struct cxgbi_sock *csk)
|
|||||||
log_debug(1 << CXGBI_DBG_PDU_RX,
|
log_debug(1 << CXGBI_DBG_PDU_RX,
|
||||||
"skb 0x%p, NOT ready 0x%lx.\n",
|
"skb 0x%p, NOT ready 0x%lx.\n",
|
||||||
skb, cxgbi_skcb_flags(skb));
|
skb, cxgbi_skcb_flags(skb));
|
||||||
read_unlock(&csk->callback_lock);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
__skb_unlink(skb, &csk->receive_queue);
|
__skb_unlink(skb, &csk->receive_queue);
|
||||||
read_unlock(&csk->callback_lock);
|
|
||||||
|
|
||||||
read += cxgbi_skcb_rx_pdulen(skb);
|
read += cxgbi_skcb_rx_pdulen(skb);
|
||||||
log_debug(1 << CXGBI_DBG_PDU_RX,
|
log_debug(1 << CXGBI_DBG_PDU_RX,
|
||||||
@@ -1739,37 +1735,66 @@ void cxgbi_conn_pdu_ready(struct cxgbi_sock *csk)
|
|||||||
|
|
||||||
if (cxgbi_skcb_test_flag(skb, SKCBF_RX_COALESCED)) {
|
if (cxgbi_skcb_test_flag(skb, SKCBF_RX_COALESCED)) {
|
||||||
err = skb_read_pdu_bhs(conn, skb);
|
err = skb_read_pdu_bhs(conn, skb);
|
||||||
if (err < 0)
|
if (err < 0) {
|
||||||
break;
|
pr_err("coalesced bhs, csk 0x%p, skb 0x%p,%u, "
|
||||||
|
"f 0x%lx, plen %u.\n",
|
||||||
|
csk, skb, skb->len,
|
||||||
|
cxgbi_skcb_flags(skb),
|
||||||
|
cxgbi_skcb_rx_pdulen(skb));
|
||||||
|
goto skb_done;
|
||||||
|
}
|
||||||
err = skb_read_pdu_data(conn, skb, skb,
|
err = skb_read_pdu_data(conn, skb, skb,
|
||||||
err + cdev->skb_rx_extra);
|
err + cdev->skb_rx_extra);
|
||||||
|
if (err < 0)
|
||||||
|
pr_err("coalesced data, csk 0x%p, skb 0x%p,%u, "
|
||||||
|
"f 0x%lx, plen %u.\n",
|
||||||
|
csk, skb, skb->len,
|
||||||
|
cxgbi_skcb_flags(skb),
|
||||||
|
cxgbi_skcb_rx_pdulen(skb));
|
||||||
} else {
|
} else {
|
||||||
err = skb_read_pdu_bhs(conn, skb);
|
err = skb_read_pdu_bhs(conn, skb);
|
||||||
if (err < 0)
|
if (err < 0) {
|
||||||
break;
|
pr_err("bhs, csk 0x%p, skb 0x%p,%u, "
|
||||||
|
"f 0x%lx, plen %u.\n",
|
||||||
|
csk, skb, skb->len,
|
||||||
|
cxgbi_skcb_flags(skb),
|
||||||
|
cxgbi_skcb_rx_pdulen(skb));
|
||||||
|
goto skb_done;
|
||||||
|
}
|
||||||
|
|
||||||
if (cxgbi_skcb_test_flag(skb, SKCBF_RX_DATA)) {
|
if (cxgbi_skcb_test_flag(skb, SKCBF_RX_DATA)) {
|
||||||
struct sk_buff *dskb;
|
struct sk_buff *dskb;
|
||||||
|
|
||||||
read_lock(&csk->callback_lock);
|
|
||||||
dskb = skb_peek(&csk->receive_queue);
|
dskb = skb_peek(&csk->receive_queue);
|
||||||
if (!dskb) {
|
if (!dskb) {
|
||||||
read_unlock(&csk->callback_lock);
|
pr_err("csk 0x%p, skb 0x%p,%u, f 0x%lx,"
|
||||||
pr_err("csk 0x%p, NO data.\n", csk);
|
" plen %u, NO data.\n",
|
||||||
err = -EAGAIN;
|
csk, skb, skb->len,
|
||||||
break;
|
cxgbi_skcb_flags(skb),
|
||||||
|
cxgbi_skcb_rx_pdulen(skb));
|
||||||
|
err = -EIO;
|
||||||
|
goto skb_done;
|
||||||
}
|
}
|
||||||
__skb_unlink(dskb, &csk->receive_queue);
|
__skb_unlink(dskb, &csk->receive_queue);
|
||||||
read_unlock(&csk->callback_lock);
|
|
||||||
|
|
||||||
err = skb_read_pdu_data(conn, skb, dskb, 0);
|
err = skb_read_pdu_data(conn, skb, dskb, 0);
|
||||||
|
if (err < 0)
|
||||||
|
pr_err("data, csk 0x%p, skb 0x%p,%u, "
|
||||||
|
"f 0x%lx, plen %u, dskb 0x%p,"
|
||||||
|
"%u.\n",
|
||||||
|
csk, skb, skb->len,
|
||||||
|
cxgbi_skcb_flags(skb),
|
||||||
|
cxgbi_skcb_rx_pdulen(skb),
|
||||||
|
dskb, dskb->len);
|
||||||
__kfree_skb(dskb);
|
__kfree_skb(dskb);
|
||||||
} else
|
} else
|
||||||
err = skb_read_pdu_data(conn, skb, skb, 0);
|
err = skb_read_pdu_data(conn, skb, skb, 0);
|
||||||
}
|
}
|
||||||
|
skb_done:
|
||||||
|
__kfree_skb(skb);
|
||||||
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
__kfree_skb(skb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log_debug(1 << CXGBI_DBG_PDU_RX, "csk 0x%p, read %u.\n", csk, read);
|
log_debug(1 << CXGBI_DBG_PDU_RX, "csk 0x%p, read %u.\n", csk, read);
|
||||||
@@ -1780,7 +1805,8 @@ void cxgbi_conn_pdu_ready(struct cxgbi_sock *csk)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
pr_info("csk 0x%p, 0x%p, rx failed %d.\n", csk, conn, err);
|
pr_info("csk 0x%p, 0x%p, rx failed %d, read %u.\n",
|
||||||
|
csk, conn, err, read);
|
||||||
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
|
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1861,7 +1887,7 @@ int cxgbi_conn_alloc_pdu(struct iscsi_task *task, u8 opcode)
|
|||||||
struct cxgbi_device *cdev = cconn->chba->cdev;
|
struct cxgbi_device *cdev = cconn->chba->cdev;
|
||||||
struct iscsi_conn *conn = task->conn;
|
struct iscsi_conn *conn = task->conn;
|
||||||
struct iscsi_tcp_task *tcp_task = task->dd_data;
|
struct iscsi_tcp_task *tcp_task = task->dd_data;
|
||||||
struct cxgbi_task_data *tdata = task->dd_data + sizeof(*tcp_task);
|
struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task);
|
||||||
struct scsi_cmnd *sc = task->sc;
|
struct scsi_cmnd *sc = task->sc;
|
||||||
int headroom = SKB_TX_ISCSI_PDU_HEADER_MAX;
|
int headroom = SKB_TX_ISCSI_PDU_HEADER_MAX;
|
||||||
|
|
||||||
@@ -1916,8 +1942,7 @@ int cxgbi_conn_init_pdu(struct iscsi_task *task, unsigned int offset,
|
|||||||
unsigned int count)
|
unsigned int count)
|
||||||
{
|
{
|
||||||
struct iscsi_conn *conn = task->conn;
|
struct iscsi_conn *conn = task->conn;
|
||||||
struct iscsi_tcp_task *tcp_task = task->dd_data;
|
struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task);
|
||||||
struct cxgbi_task_data *tdata = tcp_task->dd_data;
|
|
||||||
struct sk_buff *skb = tdata->skb;
|
struct sk_buff *skb = tdata->skb;
|
||||||
unsigned int datalen = count;
|
unsigned int datalen = count;
|
||||||
int i, padlen = iscsi_padding(count);
|
int i, padlen = iscsi_padding(count);
|
||||||
@@ -2019,8 +2044,7 @@ int cxgbi_conn_xmit_pdu(struct iscsi_task *task)
|
|||||||
{
|
{
|
||||||
struct iscsi_tcp_conn *tcp_conn = task->conn->dd_data;
|
struct iscsi_tcp_conn *tcp_conn = task->conn->dd_data;
|
||||||
struct cxgbi_conn *cconn = tcp_conn->dd_data;
|
struct cxgbi_conn *cconn = tcp_conn->dd_data;
|
||||||
struct iscsi_tcp_task *tcp_task = task->dd_data;
|
struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task);
|
||||||
struct cxgbi_task_data *tdata = tcp_task->dd_data;
|
|
||||||
struct sk_buff *skb = tdata->skb;
|
struct sk_buff *skb = tdata->skb;
|
||||||
unsigned int datalen;
|
unsigned int datalen;
|
||||||
int err;
|
int err;
|
||||||
@@ -2072,8 +2096,7 @@ EXPORT_SYMBOL_GPL(cxgbi_conn_xmit_pdu);
|
|||||||
|
|
||||||
void cxgbi_cleanup_task(struct iscsi_task *task)
|
void cxgbi_cleanup_task(struct iscsi_task *task)
|
||||||
{
|
{
|
||||||
struct cxgbi_task_data *tdata = task->dd_data +
|
struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task);
|
||||||
sizeof(struct iscsi_tcp_task);
|
|
||||||
|
|
||||||
log_debug(1 << CXGBI_DBG_ISCSI,
|
log_debug(1 << CXGBI_DBG_ISCSI,
|
||||||
"task 0x%p, skb 0x%p, itt 0x%x.\n",
|
"task 0x%p, skb 0x%p, itt 0x%x.\n",
|
||||||
@@ -2290,12 +2313,12 @@ int cxgbi_bind_conn(struct iscsi_cls_session *cls_session,
|
|||||||
/* calculate the tag idx bits needed for this conn based on cmds_max */
|
/* calculate the tag idx bits needed for this conn based on cmds_max */
|
||||||
cconn->task_idx_bits = (__ilog2_u32(conn->session->cmds_max - 1)) + 1;
|
cconn->task_idx_bits = (__ilog2_u32(conn->session->cmds_max - 1)) + 1;
|
||||||
|
|
||||||
write_lock(&csk->callback_lock);
|
write_lock_bh(&csk->callback_lock);
|
||||||
csk->user_data = conn;
|
csk->user_data = conn;
|
||||||
cconn->chba = cep->chba;
|
cconn->chba = cep->chba;
|
||||||
cconn->cep = cep;
|
cconn->cep = cep;
|
||||||
cep->cconn = cconn;
|
cep->cconn = cconn;
|
||||||
write_unlock(&csk->callback_lock);
|
write_unlock_bh(&csk->callback_lock);
|
||||||
|
|
||||||
cxgbi_conn_max_xmit_dlength(conn);
|
cxgbi_conn_max_xmit_dlength(conn);
|
||||||
cxgbi_conn_max_recv_dlength(conn);
|
cxgbi_conn_max_recv_dlength(conn);
|
||||||
|
@@ -592,6 +592,8 @@ struct cxgbi_task_data {
|
|||||||
unsigned int count;
|
unsigned int count;
|
||||||
unsigned int sgoffset;
|
unsigned int sgoffset;
|
||||||
};
|
};
|
||||||
|
#define iscsi_task_cxgbi_data(task) \
|
||||||
|
((task)->dd_data + sizeof(struct iscsi_tcp_task))
|
||||||
|
|
||||||
static inline int cxgbi_is_ddp_tag(struct cxgbi_tag_format *tformat, u32 tag)
|
static inline int cxgbi_is_ddp_tag(struct cxgbi_tag_format *tformat, u32 tag)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user