Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ebbe4421 authored by Nicholas Bellinger's avatar Nicholas Bellinger
Browse files

iser-target: Fix command leak for tx_desc->comp_llnode_batch



This patch addresses a number of active I/O shutdown issues
related to isert_cmd descriptors being leaked that are part
of a completion interrupt coalescing batch.

This includes adding logic in isert_cq_tx_comp_err() to
drain any associated tx_desc->comp_llnode_batch, as well
as isert_cq_drain_comp_llist() to drain any associated
isert_conn->conn_comp_llist.

Also, set tx_desc->llnode_active in isert_init_send_wr()
in order to determine when work requests need to be skipped
in isert_cq_tx_work() exception path code.

Finally, update isert_init_send_wr() to only allow interrupt
coalescing when ISER_CONN_UP.

Acked-by: default avatarSagi Grimberg <sagig@mellanox.com>
Cc: Or Gerlitz <ogerlitz@mellanox.com>
Cc: <stable@vger.kernel.org> #3.13+
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent 9bb4ca68
Loading
Loading
Loading
Loading
+45 −5
Original line number Diff line number Diff line
@@ -497,7 +497,6 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
	kref_init(&isert_conn->conn_kref);
	kref_get(&isert_conn->conn_kref);
	mutex_init(&isert_conn->conn_mutex);
	mutex_init(&isert_conn->conn_comp_mutex);
	spin_lock_init(&isert_conn->conn_lock);

	cma_id->context = isert_conn;
@@ -888,16 +887,17 @@ isert_init_send_wr(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
	 * Coalesce send completion interrupts by only setting IB_SEND_SIGNALED
	 * bit for every ISERT_COMP_BATCH_COUNT number of ib_post_send() calls.
	 */
	mutex_lock(&isert_conn->conn_comp_mutex);
	if (coalesce &&
	mutex_lock(&isert_conn->conn_mutex);
	if (coalesce && isert_conn->state == ISER_CONN_UP &&
	    ++isert_conn->conn_comp_batch < ISERT_COMP_BATCH_COUNT) {
		tx_desc->llnode_active = true;
		llist_add(&tx_desc->comp_llnode, &isert_conn->conn_comp_llist);
		mutex_unlock(&isert_conn->conn_comp_mutex);
		mutex_unlock(&isert_conn->conn_mutex);
		return;
	}
	isert_conn->conn_comp_batch = 0;
	tx_desc->comp_llnode_batch = llist_del_all(&isert_conn->conn_comp_llist);
	mutex_unlock(&isert_conn->conn_comp_mutex);
	mutex_unlock(&isert_conn->conn_mutex);

	send_wr->send_flags = IB_SEND_SIGNALED;
}
@@ -1692,11 +1692,46 @@ isert_send_completion(struct iser_tx_desc *tx_desc,
	__isert_send_completion(tx_desc, isert_conn);
}

static void
isert_cq_drain_comp_llist(struct isert_conn *isert_conn, struct ib_device *ib_dev)
{
	struct llist_node *llnode;
	struct isert_rdma_wr *wr;
	struct iser_tx_desc *t;

	mutex_lock(&isert_conn->conn_mutex);
	llnode = llist_del_all(&isert_conn->conn_comp_llist);
	isert_conn->conn_comp_batch = 0;
	mutex_unlock(&isert_conn->conn_mutex);

	while (llnode) {
		t = llist_entry(llnode, struct iser_tx_desc, comp_llnode);
		llnode = llist_next(llnode);
		wr = &t->isert_cmd->rdma_wr;

		atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
		isert_completion_put(t, t->isert_cmd, ib_dev);
	}
}

static void
isert_cq_tx_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn)
{
	struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
	struct isert_cmd *isert_cmd = tx_desc->isert_cmd;
	struct llist_node *llnode = tx_desc->comp_llnode_batch;
	struct isert_rdma_wr *wr;
	struct iser_tx_desc *t;

	while (llnode) {
		t = llist_entry(llnode, struct iser_tx_desc, comp_llnode);
		llnode = llist_next(llnode);
		wr = &t->isert_cmd->rdma_wr;

		atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
		isert_completion_put(t, t->isert_cmd, ib_dev);
	}
	tx_desc->comp_llnode_batch = NULL;

	if (!isert_cmd)
		isert_unmap_tx_desc(tx_desc, ib_dev);
@@ -1713,6 +1748,8 @@ isert_cq_rx_comp_err(struct isert_conn *isert_conn)
	if (isert_conn->post_recv_buf_count)
		return;

	isert_cq_drain_comp_llist(isert_conn, ib_dev);

	if (conn->sess) {
		target_sess_cmd_list_set_waiting(conn->sess->se_sess);
		target_wait_for_sess_cmds(conn->sess->se_sess);
@@ -1752,6 +1789,9 @@ isert_cq_tx_work(struct work_struct *work)
			pr_debug("TX wc.vendor_err: 0x%08x\n", wc.vendor_err);

			if (wc.wr_id != ISER_FASTREG_LI_WRID) {
				if (tx_desc->llnode_active)
					continue;

				atomic_dec(&isert_conn->post_send_buf_count);
				isert_cq_tx_comp_err(tx_desc, isert_conn);
			}
+1 −1
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ struct iser_tx_desc {
	struct isert_cmd *isert_cmd;
	struct llist_node *comp_llnode_batch;
	struct llist_node comp_llnode;
	bool		llnode_active;
	struct ib_send_wr send_wr;
} __packed;

@@ -127,7 +128,6 @@ struct isert_conn {
#define ISERT_COMP_BATCH_COUNT	8
	int			conn_comp_batch;
	struct llist_head	conn_comp_llist;
	struct mutex		conn_comp_mutex;
};

#define ISERT_MAX_CQ 64