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

Commit 2ad8099b authored by Andy Grover's avatar Andy Grover
Browse files

RDS: rds_send_xmit() locking/irq fixes



rds_message_put() cannot be called with irqs off, so move it after
irqs are re-enabled.

Spinlocks throughout the function do not to use _irqsave because
the lock of c_send_lock at top already disabled irqs.

Signed-off-by: default avatarAndy Grover <andy.grover@oracle.com>
parent 049ee3f5
Loading
Loading
Loading
Loading
+12 −9
Original line number Diff line number Diff line
@@ -168,7 +168,7 @@ int rds_send_xmit(struct rds_connection *conn)
		if (!rm) {
			unsigned int len;

			spin_lock_irqsave(&conn->c_lock, flags);
			spin_lock(&conn->c_lock);

			if (!list_empty(&conn->c_send_queue)) {
				rm = list_entry(conn->c_send_queue.next,
@@ -183,7 +183,7 @@ int rds_send_xmit(struct rds_connection *conn)
				list_move_tail(&rm->m_conn_item, &conn->c_retrans);
			}

			spin_unlock_irqrestore(&conn->c_lock, flags);
			spin_unlock(&conn->c_lock);

			if (!rm) {
				was_empty = 1;
@@ -199,11 +199,10 @@ int rds_send_xmit(struct rds_connection *conn)
			 */
			if (rm->rdma.op_active &&
			    test_bit(RDS_MSG_RETRANSMITTED, &rm->m_flags)) {
				spin_lock_irqsave(&conn->c_lock, flags);
				spin_lock(&conn->c_lock);
				if (test_and_clear_bit(RDS_MSG_ON_CONN, &rm->m_flags))
					list_move(&rm->m_conn_item, &to_be_dropped);
				spin_unlock_irqrestore(&conn->c_lock, flags);
				rds_message_put(rm);
				spin_unlock(&conn->c_lock);
				continue;
			}

@@ -326,10 +325,6 @@ int rds_send_xmit(struct rds_connection *conn)
		}
	}

	/* Nuke any messages we decided not to retransmit. */
	if (!list_empty(&to_be_dropped))
		rds_send_remove_from_sock(&to_be_dropped, RDS_RDMA_DROPPED);

	if (conn->c_trans->xmit_complete)
		conn->c_trans->xmit_complete(conn);

@@ -347,6 +342,14 @@ int rds_send_xmit(struct rds_connection *conn)
	 */
	spin_unlock_irqrestore(&conn->c_send_lock, flags);

	/* Nuke any messages we decided not to retransmit. */
	if (!list_empty(&to_be_dropped)) {
		/* irqs on here, so we can put(), unlike above */
		list_for_each_entry(rm, &to_be_dropped, m_conn_item)
			rds_message_put(rm);
		rds_send_remove_from_sock(&to_be_dropped, RDS_RDMA_DROPPED);
	}

	if (send_quota == 0 && !was_empty) {
		/* We exhausted the send quota, but there's work left to
		 * do. Return and (re-)schedule the send worker.