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

Commit 60cd6e63 authored by David S. Miller's avatar David S. Miller
Browse files

Merge tag 'rxrpc-rewrite-20160922-v2' of...

Merge tag 'rxrpc-rewrite-20160922-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs



David Howells says:

====================
rxrpc: Preparation for slow-start algorithm [ver #2]

Here are some patches that prepare for improvements in ACK generation and
for the implementation of the slow-start part of the protocol:

 (1) Stop storing the protocol header in the Tx socket buffers, but rather
     generate it on the fly.  This potentially saves a little space and
     makes it easier to alter the header just before transmission (the
     flags may get altered and the serial number has to be changed).

 (2) Mask off the Tx buffer annotations and add a flag to record which ones
     have already been resent.

 (3) Track RTT on a per-peer basis for use in future changes.  Tracepoints
     are added to log this.

 (4) Send PING ACKs in response to incoming calls to elicit a PING-RESPONSE
     ACK from which RTT data can be calculated.  The response also carries
     other useful information.

 (5) Expedite PING-RESPONSE ACK generation from sendmsg.  If we're actively
     using sendmsg, this allows us, under some circumstances, to avoid
     having to rely on the background work item to run to generate this
     ACK.

     This requires ktime_sub_ms() to be added.

 (6) Set the REQUEST-ACK flag on some DATA packets to elicit ACK-REQUESTED
     ACKs from which RTT data can be calculated.

 (7) Limit the use of pings and ACK requests for RTT determination.

Changes:

 (V2) Don't use the C division operator for 64-bit division.  One instance
      should use do_div() and the other should be using nsecs_to_jiffies().

      The last two patches got transposed, leading to an undefined symbol
      in one of them.

      Reported-by: default avatarkbuild test robot <lkp@intel.com>
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents cdd0766d fc943f67
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -231,6 +231,11 @@ static inline ktime_t ktime_sub_us(const ktime_t kt, const u64 usec)
	return ktime_sub_ns(kt, usec * NSEC_PER_USEC);
}

static inline ktime_t ktime_sub_ms(const ktime_t kt, const u64 msec)
{
	return ktime_sub_ns(kt, msec * NSEC_PER_MSEC);
}

extern ktime_t ktime_add_safe(const ktime_t lhs, const ktime_t rhs);

/**
+61 −0
Original line number Diff line number Diff line
@@ -353,6 +353,67 @@ TRACE_EVENT(rxrpc_recvmsg,
		      __entry->ret)
	    );

TRACE_EVENT(rxrpc_rtt_tx,
	    TP_PROTO(struct rxrpc_call *call, enum rxrpc_rtt_tx_trace why,
		     rxrpc_serial_t send_serial),

	    TP_ARGS(call, why, send_serial),

	    TP_STRUCT__entry(
		    __field(struct rxrpc_call *,	call		)
		    __field(enum rxrpc_rtt_tx_trace,	why		)
		    __field(rxrpc_serial_t,		send_serial	)
			     ),

	    TP_fast_assign(
		    __entry->call = call;
		    __entry->why = why;
		    __entry->send_serial = send_serial;
			   ),

	    TP_printk("c=%p %s sr=%08x",
		      __entry->call,
		      rxrpc_rtt_tx_traces[__entry->why],
		      __entry->send_serial)
	    );

TRACE_EVENT(rxrpc_rtt_rx,
	    TP_PROTO(struct rxrpc_call *call, enum rxrpc_rtt_rx_trace why,
		     rxrpc_serial_t send_serial, rxrpc_serial_t resp_serial,
		     s64 rtt, u8 nr, s64 avg),

	    TP_ARGS(call, why, send_serial, resp_serial, rtt, nr, avg),

	    TP_STRUCT__entry(
		    __field(struct rxrpc_call *,	call		)
		    __field(enum rxrpc_rtt_rx_trace,	why		)
		    __field(u8,				nr		)
		    __field(rxrpc_serial_t,		send_serial	)
		    __field(rxrpc_serial_t,		resp_serial	)
		    __field(s64,			rtt		)
		    __field(u64,			avg		)
			     ),

	    TP_fast_assign(
		    __entry->call = call;
		    __entry->why = why;
		    __entry->send_serial = send_serial;
		    __entry->resp_serial = resp_serial;
		    __entry->rtt = rtt;
		    __entry->nr = nr;
		    __entry->avg = avg;
			   ),

	    TP_printk("c=%p %s sr=%08x rr=%08x rtt=%lld nr=%u avg=%lld",
		      __entry->call,
		      rxrpc_rtt_rx_traces[__entry->why],
		      __entry->send_serial,
		      __entry->resp_serial,
		      __entry->rtt,
		      __entry->nr,
		      __entry->avg)
	    );

#endif /* _TRACE_RXRPC_H */

/* This part must be outside protection */
+34 −13
Original line number Diff line number Diff line
@@ -142,11 +142,8 @@ struct rxrpc_host_header {
 */
struct rxrpc_skb_priv {
	union {
		unsigned long	resend_at;	/* time in jiffies at which to resend */
		struct {
		u8		nr_jumbo;	/* Number of jumbo subpackets */
	};
	};
	union {
		unsigned int	offset;		/* offset into buffer of next read */
		int		remain;		/* amount of space remaining for next write */
@@ -258,10 +255,12 @@ struct rxrpc_peer {

	/* calculated RTT cache */
#define RXRPC_RTT_CACHE_SIZE 32
	suseconds_t		rtt;		/* current RTT estimate (in uS) */
	unsigned int		rtt_point;	/* next entry at which to insert */
	unsigned int		rtt_usage;	/* amount of cache actually used */
	suseconds_t		rtt_cache[RXRPC_RTT_CACHE_SIZE]; /* calculated RTT cache */
	ktime_t			rtt_last_req;	/* Time of last RTT request */
	u64			rtt;		/* Current RTT estimate (in nS) */
	u64			rtt_sum;	/* Sum of cache contents */
	u64			rtt_cache[RXRPC_RTT_CACHE_SIZE]; /* Determined RTT cache */
	u8			rtt_cursor;	/* next entry at which to insert */
	u8			rtt_usage;	/* amount of cache actually used */
};

/*
@@ -385,10 +384,9 @@ struct rxrpc_connection {
	int			debug_id;	/* debug ID for printks */
	atomic_t		serial;		/* packet serial number counter */
	unsigned int		hi_serial;	/* highest serial number received */
	u32			security_nonce;	/* response re-use preventer */
	u8			size_align;	/* data size alignment (for security) */
	u8			header_size;	/* rxrpc + security header size */
	u8			security_size;	/* security header size */
	u32			security_nonce;	/* response re-use preventer */
	u8			security_ix;	/* security type */
	u8			out_clientflag;	/* RXRPC_CLIENT_INITIATED if we are client */
};
@@ -403,6 +401,7 @@ enum rxrpc_call_flag {
	RXRPC_CALL_EXPOSED,		/* The call was exposed to the world */
	RXRPC_CALL_RX_LAST,		/* Received the last packet (at rxtx_top) */
	RXRPC_CALL_TX_LAST,		/* Last packet in Tx buffer (at rxtx_top) */
	RXRPC_CALL_PINGING,		/* Ping in process */
};

/*
@@ -487,6 +486,8 @@ struct rxrpc_call {
	u32			call_id;	/* call ID on connection  */
	u32			cid;		/* connection ID plus channel index */
	int			debug_id;	/* debug ID for printks */
	unsigned short		rx_pkt_offset;	/* Current recvmsg packet offset */
	unsigned short		rx_pkt_len;	/* Current recvmsg packet len */

	/* Rx/Tx circular buffer, depending on phase.
	 *
@@ -506,6 +507,8 @@ struct rxrpc_call {
#define RXRPC_TX_ANNO_UNACK	1
#define RXRPC_TX_ANNO_NAK	2
#define RXRPC_TX_ANNO_RETRANS	3
#define RXRPC_TX_ANNO_MASK	0x03
#define RXRPC_TX_ANNO_RESENT	0x04
#define RXRPC_RX_ANNO_JUMBO	0x3f		/* Jumbo subpacket number + 1 if not zero */
#define RXRPC_RX_ANNO_JLAST	0x40		/* Set if last element of a jumbo packet */
#define RXRPC_RX_ANNO_VERIFIED	0x80		/* Set if verified and decrypted */
@@ -528,8 +531,8 @@ struct rxrpc_call {
	u16			ackr_skew;	/* skew on packet being ACK'd */
	rxrpc_serial_t		ackr_serial;	/* serial of packet being ACK'd */
	rxrpc_seq_t		ackr_prev_seq;	/* previous sequence number received */
	unsigned short		rx_pkt_offset;	/* Current recvmsg packet offset */
	unsigned short		rx_pkt_len;	/* Current recvmsg packet len */
	rxrpc_serial_t		ackr_ping;	/* Last ping sent */
	ktime_t			ackr_ping_time;	/* Time last ping sent */

	/* transmission-phase ACK management */
	rxrpc_serial_t		acks_latest;	/* serial number of latest ACK received */
@@ -656,6 +659,22 @@ enum rxrpc_recvmsg_trace {

extern const char rxrpc_recvmsg_traces[rxrpc_recvmsg__nr_trace][5];

enum rxrpc_rtt_tx_trace {
	rxrpc_rtt_tx_ping,
	rxrpc_rtt_tx_data,
	rxrpc_rtt_tx__nr_trace
};

extern const char rxrpc_rtt_tx_traces[rxrpc_rtt_tx__nr_trace][5];

enum rxrpc_rtt_rx_trace {
	rxrpc_rtt_rx_ping_response,
	rxrpc_rtt_rx_requested_ack,
	rxrpc_rtt_rx__nr_trace
};

extern const char rxrpc_rtt_rx_traces[rxrpc_rtt_rx__nr_trace][5];

extern const char *const rxrpc_pkts[];
extern const char *rxrpc_acks(u8 reason);

@@ -946,7 +965,7 @@ extern const s8 rxrpc_ack_priority[];
 * output.c
 */
int rxrpc_send_call_packet(struct rxrpc_call *, u8);
int rxrpc_send_data_packet(struct rxrpc_connection *, struct sk_buff *);
int rxrpc_send_data_packet(struct rxrpc_call *, struct sk_buff *);
void rxrpc_reject_packets(struct rxrpc_local *);

/*
@@ -954,6 +973,8 @@ void rxrpc_reject_packets(struct rxrpc_local *);
 */
void rxrpc_error_report(struct sock *);
void rxrpc_peer_error_distributor(struct work_struct *);
void rxrpc_peer_add_rtt(struct rxrpc_call *, enum rxrpc_rtt_rx_trace,
			rxrpc_serial_t, rxrpc_serial_t, ktime_t, ktime_t);

/*
 * peer_object.c
+29 −27
Original line number Diff line number Diff line
@@ -139,16 +139,17 @@ void rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason,
 */
static void rxrpc_resend(struct rxrpc_call *call)
{
	struct rxrpc_wire_header *whdr;
	struct rxrpc_skb_priv *sp;
	struct sk_buff *skb;
	rxrpc_seq_t cursor, seq, top;
	unsigned long resend_at, now;
	ktime_t now = ktime_get_real(), max_age, oldest,  resend_at;
	int ix;
	u8 annotation;
	u8 annotation, anno_type;

	_enter("{%d,%d}", call->tx_hard_ack, call->tx_top);

	max_age = ktime_sub_ms(now, rxrpc_resend_timeout);

	spin_lock_bh(&call->lock);

	cursor = call->tx_hard_ack;
@@ -161,31 +162,33 @@ static void rxrpc_resend(struct rxrpc_call *call)
	 * the packets in the Tx buffer we're going to resend and what the new
	 * resend timeout will be.
	 */
	now = jiffies;
	resend_at = now + rxrpc_resend_timeout;
	oldest = now;
	for (seq = cursor + 1; before_eq(seq, top); seq++) {
		ix = seq & RXRPC_RXTX_BUFF_MASK;
		annotation = call->rxtx_annotations[ix];
		if (annotation == RXRPC_TX_ANNO_ACK)
		anno_type = annotation & RXRPC_TX_ANNO_MASK;
		annotation &= ~RXRPC_TX_ANNO_MASK;
		if (anno_type == RXRPC_TX_ANNO_ACK)
			continue;

		skb = call->rxtx_buffer[ix];
		rxrpc_see_skb(skb, rxrpc_skb_tx_seen);
		sp = rxrpc_skb(skb);

		if (annotation == RXRPC_TX_ANNO_UNACK) {
			if (time_after(sp->resend_at, now)) {
				if (time_before(sp->resend_at, resend_at))
					resend_at = sp->resend_at;
		if (anno_type == RXRPC_TX_ANNO_UNACK) {
			if (ktime_after(skb->tstamp, max_age)) {
				if (ktime_before(skb->tstamp, oldest))
					oldest = skb->tstamp;
				continue;
			}
		}

		/* Okay, we need to retransmit a packet. */
		call->rxtx_annotations[ix] = RXRPC_TX_ANNO_RETRANS;
		call->rxtx_annotations[ix] = RXRPC_TX_ANNO_RETRANS | annotation;
	}

	call->resend_at = resend_at;
	resend_at = ktime_sub(ktime_add_ns(oldest, rxrpc_resend_timeout), now);
	call->resend_at = jiffies + nsecs_to_jiffies(ktime_to_ns(resend_at));

	/* Now go through the Tx window and perform the retransmissions.  We
	 * have to drop the lock for each send.  If an ACK comes in whilst the
@@ -195,29 +198,21 @@ static void rxrpc_resend(struct rxrpc_call *call)
	for (seq = cursor + 1; before_eq(seq, top); seq++) {
		ix = seq & RXRPC_RXTX_BUFF_MASK;
		annotation = call->rxtx_annotations[ix];
		if (annotation != RXRPC_TX_ANNO_RETRANS)
		anno_type = annotation & RXRPC_TX_ANNO_MASK;
		if (anno_type != RXRPC_TX_ANNO_RETRANS)
			continue;

		skb = call->rxtx_buffer[ix];
		rxrpc_get_skb(skb, rxrpc_skb_tx_got);
		spin_unlock_bh(&call->lock);
		sp = rxrpc_skb(skb);

		/* Each Tx packet needs a new serial number */
		sp->hdr.serial = atomic_inc_return(&call->conn->serial);

		whdr = (struct rxrpc_wire_header *)skb->head;
		whdr->serial = htonl(sp->hdr.serial);

		if (rxrpc_send_data_packet(call->conn, skb) < 0) {
			call->resend_at = now + 2;
		if (rxrpc_send_data_packet(call, skb) < 0) {
			rxrpc_free_skb(skb, rxrpc_skb_tx_freed);
			return;
		}

		if (rxrpc_is_client_call(call))
			rxrpc_expose_client_call(call);
		sp->resend_at = now + rxrpc_resend_timeout;

		rxrpc_free_skb(skb, rxrpc_skb_tx_freed);
		spin_lock_bh(&call->lock);
@@ -227,10 +222,17 @@ static void rxrpc_resend(struct rxrpc_call *call)
		 * received and the packet might have been hard-ACK'd (in which
		 * case it will no longer be in the buffer).
		 */
		if (after(seq, call->tx_hard_ack) &&
		    (call->rxtx_annotations[ix] == RXRPC_TX_ANNO_RETRANS ||
		     call->rxtx_annotations[ix] == RXRPC_TX_ANNO_NAK))
			call->rxtx_annotations[ix] = RXRPC_TX_ANNO_UNACK;
		if (after(seq, call->tx_hard_ack)) {
			annotation = call->rxtx_annotations[ix];
			anno_type = annotation & RXRPC_TX_ANNO_MASK;
			if (anno_type == RXRPC_TX_ANNO_RETRANS ||
			    anno_type == RXRPC_TX_ANNO_NAK) {
				annotation &= ~RXRPC_TX_ANNO_MASK;
				annotation |= RXRPC_TX_ANNO_UNACK;
			}
			annotation |= RXRPC_TX_ANNO_RESENT;
			call->rxtx_annotations[ix] = annotation;
		}

		if (after(call->tx_hard_ack, seq))
			seq = call->tx_hard_ack;
+0 −1
Original line number Diff line number Diff line
@@ -53,7 +53,6 @@ struct rxrpc_connection *rxrpc_alloc_connection(gfp_t gfp)
		spin_lock_init(&conn->state_lock);
		conn->debug_id = atomic_inc_return(&rxrpc_debug_id);
		conn->size_align = 4;
		conn->header_size = sizeof(struct rxrpc_wire_header);
		conn->idle_timestamp = jiffies;
	}

Loading