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

Commit de8474eb authored by Stefan Raspl's avatar Stefan Raspl Committed by David S. Miller
Browse files

net/smc: urgent data support



Add support for out of band data send and receive.

Signed-off-by: default avatarStefan Raspl <raspl@linux.ibm.com>
Signed-off-by: default avatarUrsula Braun <ubraun@linux.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b9f227c3
Loading
Loading
Loading
Loading
+22 −2
Original line number Diff line number Diff line
@@ -8,8 +8,6 @@
 *
 *  Initial restrictions:
 *    - support for alternate links postponed
 *    - partial support for non-blocking sockets only
 *    - support for urgent data postponed
 *
 *  Copyright IBM Corp. 2016, 2018
 *
@@ -1338,6 +1336,8 @@ static __poll_t smc_poll(struct file *file, struct socket *sock,
			if (sk->sk_state == SMC_APPCLOSEWAIT1)
				mask |= EPOLLIN;
		}
		if (smc->conn.urg_state == SMC_URG_VALID)
			mask |= EPOLLPRI;

	}
	release_sock(sk);
@@ -1477,10 +1477,13 @@ static int smc_getsockopt(struct socket *sock, int level, int optname,
static int smc_ioctl(struct socket *sock, unsigned int cmd,
		     unsigned long arg)
{
	union smc_host_cursor cons, urg;
	struct smc_connection *conn;
	struct smc_sock *smc;
	int answ;

	smc = smc_sk(sock->sk);
	conn = &smc->conn;
	if (smc->use_fallback) {
		if (!smc->clcsock)
			return -EBADF;
@@ -1517,6 +1520,23 @@ static int smc_ioctl(struct socket *sock, unsigned int cmd,
		else
			answ = smc_tx_prepared_sends(&smc->conn);
		break;
	case SIOCATMARK:
		if (smc->sk.sk_state == SMC_LISTEN)
			return -EINVAL;
		if (smc->sk.sk_state == SMC_INIT ||
		    smc->sk.sk_state == SMC_CLOSED) {
			answ = 0;
		} else {
			smc_curs_write(&cons,
			       smc_curs_read(&conn->local_tx_ctrl.cons, conn),
				       conn);
			smc_curs_write(&urg,
				       smc_curs_read(&conn->urg_curs, conn),
				       conn);
			answ = smc_curs_diff(conn->rmb_desc->len,
					     &cons, &urg) == 1;
		}
		break;
	default:
		return -ENOIOCTLCMD;
	}
+15 −0
Original line number Diff line number Diff line
@@ -114,6 +114,12 @@ struct smc_host_cdc_msg { /* Connection Data Control message */
	u8				reserved[18];
} __aligned(8);

enum smc_urg_state {
	SMC_URG_VALID,			/* data present */
	SMC_URG_NOTYET,			/* data pending */
	SMC_URG_READ			/* data was already read */
};

struct smc_connection {
	struct rb_node		alert_node;
	struct smc_link_group	*lgr;		/* link group of connection */
@@ -160,6 +166,15 @@ struct smc_connection {
	union smc_host_cursor	rx_curs_confirmed; /* confirmed to peer
						    * source of snd_una ?
						    */
	union smc_host_cursor	urg_curs;	/* points at urgent byte */
	enum smc_urg_state	urg_state;
	bool			urg_tx_pend;	/* urgent data staged */
	bool			urg_rx_skip_pend;
						/* indicate urgent oob data
						 * read, but previous regular
						 * data still pending
						 */
	char			urg_rx_byte;	/* urgent byte */
	atomic_t		bytes_to_rcv;	/* arrived data,
						 * not yet received
						 */
+41 −3
Original line number Diff line number Diff line
@@ -164,6 +164,28 @@ static inline bool smc_cdc_before(u16 seq1, u16 seq2)
	return (s16)(seq1 - seq2) < 0;
}

static void smc_cdc_handle_urg_data_arrival(struct smc_sock *smc,
					    int *diff_prod)
{
	struct smc_connection *conn = &smc->conn;
	char *base;

	/* new data included urgent business */
	smc_curs_write(&conn->urg_curs,
		       smc_curs_read(&conn->local_rx_ctrl.prod, conn),
		       conn);
	conn->urg_state = SMC_URG_VALID;
	if (!sock_flag(&smc->sk, SOCK_URGINLINE))
		/* we'll skip the urgent byte, so don't account for it */
		(*diff_prod)--;
	base = (char *)conn->rmb_desc->cpu_addr;
	if (conn->urg_curs.count)
		conn->urg_rx_byte = *(base + conn->urg_curs.count - 1);
	else
		conn->urg_rx_byte = *(base + conn->rmb_desc->len - 1);
	sk_send_sigurg(&smc->sk);
}

static void smc_cdc_msg_recv_action(struct smc_sock *smc,
				    struct smc_cdc_msg *cdc)
{
@@ -194,15 +216,25 @@ static void smc_cdc_msg_recv_action(struct smc_sock *smc,
	diff_prod = smc_curs_diff(conn->rmb_desc->len, &prod_old,
				  &conn->local_rx_ctrl.prod);
	if (diff_prod) {
		if (conn->local_rx_ctrl.prod_flags.urg_data_present)
			smc_cdc_handle_urg_data_arrival(smc, &diff_prod);
		/* bytes_to_rcv is decreased in smc_recvmsg */
		smp_mb__before_atomic();
		atomic_add(diff_prod, &conn->bytes_to_rcv);
		/* guarantee 0 <= bytes_to_rcv <= rmb_desc->len */
		smp_mb__after_atomic();
		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);
	} else {
		if (conn->local_rx_ctrl.prod_flags.write_blocked ||
		    conn->local_rx_ctrl.prod_flags.cons_curs_upd_req ||
		    conn->local_rx_ctrl.prod_flags.urg_data_pending) {
			if (conn->local_rx_ctrl.prod_flags.urg_data_pending)
				conn->urg_state = SMC_URG_NOTYET;
			/* force immediate tx of current consumer cursor, but
			 * under send_lock to guarantee arrival in seqno-order
			 */
			smc_tx_sndbuf_nonempty(conn);
		}
	}

	/* piggy backed tx info */
@@ -212,6 +244,12 @@ static void smc_cdc_msg_recv_action(struct smc_sock *smc,
		/* trigger socket release if connection closed */
		smc_close_wake_tx_prepared(smc);
	}
	if (diff_cons && conn->urg_tx_pend &&
	    atomic_read(&conn->peer_rmbe_space) == conn->peer_rmbe_size) {
		/* urg data confirmed by peer, indicate we're ready for more */
		conn->urg_tx_pend = false;
		smc->sk.sk_write_space(&smc->sk);
	}

	if (conn->local_rx_ctrl.conn_state_flags.peer_conn_abort) {
		smc->sk.sk_err = ECONNRESET;
+13 −0
Original line number Diff line number Diff line
@@ -146,6 +146,19 @@ static inline int smc_curs_diff(unsigned int size,
	return max_t(int, 0, (new->count - old->count));
}

/* calculate cursor difference between old and new - returns negative
 * value in case old > new
 */
static inline int smc_curs_comp(unsigned int size,
				union smc_host_cursor *old,
				union smc_host_cursor *new)
{
	if (old->wrap > new->wrap ||
	    (old->wrap == new->wrap && old->count > new->count))
		return -smc_curs_diff(size, new, old);
	return smc_curs_diff(size, old, new);
}

static inline void smc_host_cursor_to_cdc(union smc_cdc_cursor *peer,
					  union smc_host_cursor *local,
					  struct smc_connection *conn)
+1 −0
Original line number Diff line number Diff line
@@ -544,6 +544,7 @@ int smc_conn_create(struct smc_sock *smc,
	}
	conn->local_tx_ctrl.common.type = SMC_CDC_MSG_TYPE;
	conn->local_tx_ctrl.len = SMC_WR_TX_SIZE;
	conn->urg_state = SMC_URG_READ;
#ifndef KERNEL_HAS_ATOMIC64
	spin_lock_init(&conn->acurs_lock);
#endif
Loading