Skip to content

Commit

Permalink
[SCSI] libcxgbi: pdu read fixes
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
kxie@chelsio.com authored and James Bottomley committed Oct 7, 2010
1 parent 24d3f95 commit e3d2ad8
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 28 deletions.
79 changes: 51 additions & 28 deletions drivers/scsi/cxgbi/libcxgbi.c
Original file line number Diff line number Diff line change
Expand Up @@ -593,11 +593,11 @@ static void cxgbi_inform_iscsi_conn_closing(struct cxgbi_sock *csk)
csk, csk->state, csk->flags, csk->user_data);

if (csk->state != CTP_ESTABLISHED) {
read_lock(&csk->callback_lock);
read_lock_bh(&csk->callback_lock);
if (csk->user_data)
iscsi_conn_failure(csk->user_data,
ISCSI_ERR_CONN_FAILED);
read_unlock(&csk->callback_lock);
read_unlock_bh(&csk->callback_lock);
}
}

Expand Down Expand Up @@ -1712,24 +1712,20 @@ void cxgbi_conn_pdu_ready(struct cxgbi_sock *csk)
"csk 0x%p, conn 0x%p, id %d, suspend_rx %lu!\n",
csk, conn, conn ? conn->id : 0xFF,
conn ? conn->suspend_rx : 0xFF);
read_unlock(&csk->callback_lock);
return;
}

while (!err) {
read_lock(&csk->callback_lock);
skb = skb_peek(&csk->receive_queue);
if (!skb ||
!(cxgbi_skcb_test_flag(skb, SKCBF_RX_STATUS))) {
if (skb)
log_debug(1 << CXGBI_DBG_PDU_RX,
"skb 0x%p, NOT ready 0x%lx.\n",
skb, cxgbi_skcb_flags(skb));
read_unlock(&csk->callback_lock);
break;
}
__skb_unlink(skb, &csk->receive_queue);
read_unlock(&csk->callback_lock);

read += cxgbi_skcb_rx_pdulen(skb);
log_debug(1 << CXGBI_DBG_PDU_RX,
Expand All @@ -1739,37 +1735,66 @@ void cxgbi_conn_pdu_ready(struct cxgbi_sock *csk)

if (cxgbi_skcb_test_flag(skb, SKCBF_RX_COALESCED)) {
err = skb_read_pdu_bhs(conn, skb);
if (err < 0)
break;
if (err < 0) {
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 + 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 {
err = skb_read_pdu_bhs(conn, skb);
if (err < 0)
break;
if (err < 0) {
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)) {
struct sk_buff *dskb;

read_lock(&csk->callback_lock);
dskb = skb_peek(&csk->receive_queue);
if (!dskb) {
read_unlock(&csk->callback_lock);
pr_err("csk 0x%p, NO data.\n", csk);
err = -EAGAIN;
break;
pr_err("csk 0x%p, skb 0x%p,%u, f 0x%lx,"
" plen %u, NO data.\n",
csk, skb, skb->len,
cxgbi_skcb_flags(skb),
cxgbi_skcb_rx_pdulen(skb));
err = -EIO;
goto skb_done;
}
__skb_unlink(dskb, &csk->receive_queue);
read_unlock(&csk->callback_lock);

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);
} else
err = skb_read_pdu_data(conn, skb, skb, 0);
}
skb_done:
__kfree_skb(skb);

if (err < 0)
break;

__kfree_skb(skb);
}

log_debug(1 << CXGBI_DBG_PDU_RX, "csk 0x%p, read %u.\n", csk, read);
Expand All @@ -1780,7 +1805,8 @@ void cxgbi_conn_pdu_ready(struct cxgbi_sock *csk)
}

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);
}
}
Expand Down Expand Up @@ -1861,7 +1887,7 @@ int cxgbi_conn_alloc_pdu(struct iscsi_task *task, u8 opcode)
struct cxgbi_device *cdev = cconn->chba->cdev;
struct iscsi_conn *conn = task->conn;
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;
int headroom = SKB_TX_ISCSI_PDU_HEADER_MAX;

Expand Down Expand Up @@ -1916,8 +1942,7 @@ int cxgbi_conn_init_pdu(struct iscsi_task *task, unsigned int offset,
unsigned int count)
{
struct iscsi_conn *conn = task->conn;
struct iscsi_tcp_task *tcp_task = task->dd_data;
struct cxgbi_task_data *tdata = tcp_task->dd_data;
struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task);
struct sk_buff *skb = tdata->skb;
unsigned int datalen = count;
int i, padlen = iscsi_padding(count);
Expand Down Expand Up @@ -2019,8 +2044,7 @@ int cxgbi_conn_xmit_pdu(struct iscsi_task *task)
{
struct iscsi_tcp_conn *tcp_conn = task->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 = tcp_task->dd_data;
struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task);
struct sk_buff *skb = tdata->skb;
unsigned int datalen;
int err;
Expand Down Expand Up @@ -2072,8 +2096,7 @@ EXPORT_SYMBOL_GPL(cxgbi_conn_xmit_pdu);

void cxgbi_cleanup_task(struct iscsi_task *task)
{
struct cxgbi_task_data *tdata = task->dd_data +
sizeof(struct iscsi_tcp_task);
struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task);

log_debug(1 << CXGBI_DBG_ISCSI,
"task 0x%p, skb 0x%p, itt 0x%x.\n",
Expand Down Expand Up @@ -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 */
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;
cconn->chba = cep->chba;
cconn->cep = cep;
cep->cconn = cconn;
write_unlock(&csk->callback_lock);
write_unlock_bh(&csk->callback_lock);

cxgbi_conn_max_xmit_dlength(conn);
cxgbi_conn_max_recv_dlength(conn);
Expand Down
2 changes: 2 additions & 0 deletions drivers/scsi/cxgbi/libcxgbi.h
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,8 @@ struct cxgbi_task_data {
unsigned int count;
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)
{
Expand Down

0 comments on commit e3d2ad8

Please sign in to comment.