diff options
Diffstat (limited to 'drivers/target/iscsi')
-rw-r--r-- | drivers/target/iscsi/cxgbit/cxgbit.h | 1 | ||||
-rw-r--r-- | drivers/target/iscsi/cxgbit/cxgbit_cm.c | 34 | ||||
-rw-r--r-- | drivers/target/iscsi/cxgbit/cxgbit_target.c | 24 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_nego.c | 36 |
4 files changed, 59 insertions, 36 deletions
diff --git a/drivers/target/iscsi/cxgbit/cxgbit.h b/drivers/target/iscsi/cxgbit/cxgbit.h index c04cd0832dec..406903398dfd 100644 --- a/drivers/target/iscsi/cxgbit/cxgbit.h +++ b/drivers/target/iscsi/cxgbit/cxgbit.h @@ -207,7 +207,6 @@ struct cxgbit_sock { /* socket lock */ spinlock_t lock; wait_queue_head_t waitq; - wait_queue_head_t ack_waitq; bool lock_owner; struct kref kref; u32 max_iso_npdu; diff --git a/drivers/target/iscsi/cxgbit/cxgbit_cm.c b/drivers/target/iscsi/cxgbit/cxgbit_cm.c index a2b5c796bbc4..518ded214e74 100644 --- a/drivers/target/iscsi/cxgbit/cxgbit_cm.c +++ b/drivers/target/iscsi/cxgbit/cxgbit_cm.c @@ -1360,7 +1360,6 @@ cxgbit_pass_accept_req(struct cxgbit_device *cdev, struct sk_buff *skb) cxgbit_sock_reset_wr_list(csk); spin_lock_init(&csk->lock); init_waitqueue_head(&csk->waitq); - init_waitqueue_head(&csk->ack_waitq); csk->lock_owner = false; if (cxgbit_alloc_csk_skb(csk)) { @@ -1485,6 +1484,26 @@ u32 cxgbit_send_tx_flowc_wr(struct cxgbit_sock *csk) return flowclen16; } +static int +cxgbit_send_tcb_skb(struct cxgbit_sock *csk, struct sk_buff *skb) +{ + spin_lock_bh(&csk->lock); + if (unlikely(csk->com.state != CSK_STATE_ESTABLISHED)) { + spin_unlock_bh(&csk->lock); + pr_err("%s: csk 0x%p, tid %u, state %u\n", + __func__, csk, csk->tid, csk->com.state); + __kfree_skb(skb); + return -1; + } + + cxgbit_get_csk(csk); + cxgbit_init_wr_wait(&csk->com.wr_wait); + cxgbit_ofld_send(csk->com.cdev, skb); + spin_unlock_bh(&csk->lock); + + return 0; +} + int cxgbit_setup_conn_digest(struct cxgbit_sock *csk) { struct sk_buff *skb; @@ -1510,10 +1529,8 @@ int cxgbit_setup_conn_digest(struct cxgbit_sock *csk) (dcrc ? ULP_CRC_DATA : 0)) << 4); set_wr_txq(skb, CPL_PRIORITY_CONTROL, csk->ctrlq_idx); - cxgbit_get_csk(csk); - cxgbit_init_wr_wait(&csk->com.wr_wait); - - cxgbit_ofld_send(csk->com.cdev, skb); + if (cxgbit_send_tcb_skb(csk, skb)) + return -1; ret = cxgbit_wait_for_reply(csk->com.cdev, &csk->com.wr_wait, @@ -1545,10 +1562,8 @@ int cxgbit_setup_conn_pgidx(struct cxgbit_sock *csk, u32 pg_idx) req->val = cpu_to_be64(pg_idx << 8); set_wr_txq(skb, CPL_PRIORITY_CONTROL, csk->ctrlq_idx); - cxgbit_get_csk(csk); - cxgbit_init_wr_wait(&csk->com.wr_wait); - - cxgbit_ofld_send(csk->com.cdev, skb); + if (cxgbit_send_tcb_skb(csk, skb)) + return -1; ret = cxgbit_wait_for_reply(csk->com.cdev, &csk->com.wr_wait, @@ -1871,7 +1886,6 @@ static void cxgbit_fw4_ack(struct cxgbit_sock *csk, struct sk_buff *skb) if (csk->snd_una != snd_una) { csk->snd_una = snd_una; dst_confirm(csk->dst); - wake_up(&csk->ack_waitq); } } diff --git a/drivers/target/iscsi/cxgbit/cxgbit_target.c b/drivers/target/iscsi/cxgbit/cxgbit_target.c index fcdc4211e3c2..9b3eb2e8c92a 100644 --- a/drivers/target/iscsi/cxgbit/cxgbit_target.c +++ b/drivers/target/iscsi/cxgbit/cxgbit_target.c @@ -284,18 +284,6 @@ void cxgbit_push_tx_frames(struct cxgbit_sock *csk) } } -static bool cxgbit_lock_sock(struct cxgbit_sock *csk) -{ - spin_lock_bh(&csk->lock); - - if (before(csk->write_seq, csk->snd_una + csk->snd_win)) - csk->lock_owner = true; - - spin_unlock_bh(&csk->lock); - - return csk->lock_owner; -} - static void cxgbit_unlock_sock(struct cxgbit_sock *csk) { struct sk_buff_head backlogq; @@ -325,20 +313,16 @@ static int cxgbit_queue_skb(struct cxgbit_sock *csk, struct sk_buff *skb) { int ret = 0; - wait_event_interruptible(csk->ack_waitq, cxgbit_lock_sock(csk)); + spin_lock_bh(&csk->lock); + csk->lock_owner = true; + spin_unlock_bh(&csk->lock); if (unlikely((csk->com.state != CSK_STATE_ESTABLISHED) || signal_pending(current))) { __kfree_skb(skb); __skb_queue_purge(&csk->ppodq); ret = -1; - spin_lock_bh(&csk->lock); - if (csk->lock_owner) { - spin_unlock_bh(&csk->lock); - goto unlock; - } - spin_unlock_bh(&csk->lock); - return ret; + goto unlock; } csk->write_seq += skb->len + diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index 685d771b51d4..f88a52fec889 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -481,7 +481,7 @@ static bool __iscsi_target_sk_check_close(struct sock *sk) { if (sk->sk_state == TCP_CLOSE_WAIT || sk->sk_state == TCP_CLOSE) { pr_debug("__iscsi_target_sk_check_close: TCP_CLOSE_WAIT|TCP_CLOSE," - "returning FALSE\n"); + "returning TRUE\n"); return true; } return false; @@ -625,13 +625,37 @@ static void iscsi_target_do_login_rx(struct work_struct *work) pr_debug("iscsi_target_do_login_rx after rx_login_io, %p, %s:%d\n", conn, current->comm, current->pid); + /* + * LOGIN_FLAGS_READ_ACTIVE is cleared so that sk_data_ready + * could be triggered again after this. + * + * LOGIN_FLAGS_WRITE_ACTIVE is cleared after we successfully + * process a login PDU, so that sk_state_chage can do login + * cleanup as needed if the socket is closed. If a delayed work is + * ongoing (LOGIN_FLAGS_WRITE_ACTIVE or LOGIN_FLAGS_READ_ACTIVE), + * sk_state_change will leave the cleanup to the delayed work or + * it will schedule a delayed work to do cleanup. + */ + if (conn->sock) { + struct sock *sk = conn->sock->sk; + + write_lock_bh(&sk->sk_callback_lock); + if (!test_bit(LOGIN_FLAGS_INITIAL_PDU, &conn->login_flags)) { + clear_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags); + set_bit(LOGIN_FLAGS_WRITE_ACTIVE, &conn->login_flags); + } + write_unlock_bh(&sk->sk_callback_lock); + } + rc = iscsi_target_do_login(conn, login); if (rc < 0) { goto err; } else if (!rc) { - if (iscsi_target_sk_check_and_clear(conn, LOGIN_FLAGS_READ_ACTIVE)) + if (iscsi_target_sk_check_and_clear(conn, + LOGIN_FLAGS_WRITE_ACTIVE)) goto err; } else if (rc == 1) { + cancel_delayed_work(&conn->login_work); iscsi_target_nego_release(conn); iscsi_post_login_handler(np, conn, zero_tsih); iscsit_deaccess_np(np, tpg, tpg_np); @@ -640,6 +664,7 @@ static void iscsi_target_do_login_rx(struct work_struct *work) err: iscsi_target_restore_sock_callbacks(conn); + cancel_delayed_work(&conn->login_work); iscsi_target_login_drop(conn, login); iscsit_deaccess_np(np, tpg, tpg_np); } @@ -670,9 +695,10 @@ static void iscsi_target_sk_state_change(struct sock *sk) state = __iscsi_target_sk_check_close(sk); pr_debug("__iscsi_target_sk_close_change: state: %d\n", state); - if (test_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags)) { - pr_debug("Got LOGIN_FLAGS_READ_ACTIVE=1 sk_state_change" - " conn: %p\n", conn); + if (test_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags) || + test_bit(LOGIN_FLAGS_WRITE_ACTIVE, &conn->login_flags)) { + pr_debug("Got LOGIN_FLAGS_{READ|WRITE}_ACTIVE=1" + " sk_state_change conn: %p\n", conn); if (state) set_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags); write_unlock_bh(&sk->sk_callback_lock); |