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

Commit 6b5771aa authored by Ursula Braun's avatar Ursula Braun Committed by David S. Miller
Browse files

smc: no consumer update in tasklet context



The SMC protocol requires to send a separate consumer cursor update,
if it cannot be piggybacked to updates of the producer cursor.
When receiving a blocked signal from the sender, this update is sent
already in tasklet context. In addition consumer cursor updates are
sent after data receival.
Sending of cursor updates is controlled by sequence numbers.
Assuming receiving stray messages the receiver drops updates with older
sequence numbers than an already received cursor update with a higher
sequence number.
Sending consumer cursor updates in tasklet context may result in
wrong order sends and its corresponding drops at the receiver. Since
it is sufficient to send consumer cursor updates once the data is
received, this patch gets rid of the consumer cursor update in tasklet
context to guarantee in-sequence arrival of cursor updates.

Signed-off-by: default avatarUrsula Braun <ubraun@linux.vnet.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 71c125c3
Loading
Loading
Loading
Loading
+3 −9
Original line number Original line Diff line number Diff line
@@ -213,6 +213,9 @@ static void smc_cdc_msg_recv_action(struct smc_sock *smc,
		/* guarantee 0 <= bytes_to_rcv <= rmbe_size */
		/* guarantee 0 <= bytes_to_rcv <= rmbe_size */
		smp_mb__after_atomic();
		smp_mb__after_atomic();
		smc->sk.sk_data_ready(&smc->sk);
		smc->sk.sk_data_ready(&smc->sk);
	} else if ((conn->local_rx_ctrl.prod_flags.write_blocked) ||
		   (conn->local_rx_ctrl.prod_flags.cons_curs_upd_req)) {
		smc->sk.sk_data_ready(&smc->sk);
	}
	}


	if (conn->local_rx_ctrl.conn_state_flags.peer_conn_abort) {
	if (conn->local_rx_ctrl.conn_state_flags.peer_conn_abort) {
@@ -234,15 +237,6 @@ static void smc_cdc_msg_recv_action(struct smc_sock *smc,
		/* trigger socket release if connection closed */
		/* trigger socket release if connection closed */
		smc_close_wake_tx_prepared(smc);
		smc_close_wake_tx_prepared(smc);
	}
	}

	/* socket connected but not accepted */
	if (!smc->sk.sk_socket)
		return;

	/* data available */
	if ((conn->local_rx_ctrl.prod_flags.write_blocked) ||
	    (conn->local_rx_ctrl.prod_flags.cons_curs_upd_req))
		smc_tx_consumer_update(conn);
}
}


/* called under tasklet context */
/* called under tasklet context */
+2 −7
Original line number Original line Diff line number Diff line
@@ -448,9 +448,7 @@ static void smc_tx_work(struct work_struct *work)
void smc_tx_consumer_update(struct smc_connection *conn)
void smc_tx_consumer_update(struct smc_connection *conn)
{
{
	union smc_host_cursor cfed, cons;
	union smc_host_cursor cfed, cons;
	struct smc_cdc_tx_pend *pend;
	int to_confirm;
	struct smc_wr_buf *wr_buf;
	int to_confirm, rc;


	smc_curs_write(&cons,
	smc_curs_write(&cons,
		       smc_curs_read(&conn->local_tx_ctrl.cons, conn),
		       smc_curs_read(&conn->local_tx_ctrl.cons, conn),
@@ -464,10 +462,7 @@ void smc_tx_consumer_update(struct smc_connection *conn)
	    ((to_confirm > conn->rmbe_update_limit) &&
	    ((to_confirm > conn->rmbe_update_limit) &&
	     ((to_confirm > (conn->rmbe_size / 2)) ||
	     ((to_confirm > (conn->rmbe_size / 2)) ||
	      conn->local_rx_ctrl.prod_flags.write_blocked))) {
	      conn->local_rx_ctrl.prod_flags.write_blocked))) {
		rc = smc_cdc_get_free_slot(conn, &wr_buf, &pend);
		if (smc_cdc_get_slot_and_msg_send(conn) < 0) {
		if (!rc)
			rc = smc_cdc_msg_send(conn, wr_buf, pend);
		if (rc < 0) {
			schedule_delayed_work(&conn->tx_work,
			schedule_delayed_work(&conn->tx_work,
					      SMC_TX_WORK_DELAY);
					      SMC_TX_WORK_DELAY);
			return;
			return;